blob: 651f4a77fc54037813c2f14a36b7e08d2f01ff41 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
32
Michal Vaskof9b35d92016-10-21 15:19:30 +020033static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
34
Michal Vaskod24dd012016-09-30 12:20:22 +020035int
36parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020037{
38 const char *ptr;
39 int minus = 0;
40 int64_t ret = 0;
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;
1258};
1259
Radek Krejci9ff0a922016-07-14 13:08:05 +02001260void
1261resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1262{
1263 unsigned int e = 0, f = 0, r = 0;
1264 uint8_t op;
1265
1266 assert(iffeat);
1267
1268 if (!iffeat->expr) {
1269 goto result;
1270 }
1271
1272 do {
1273 op = iff_getop(iffeat->expr, e++);
1274 switch (op) {
1275 case LYS_IFF_NOT:
1276 if (!r) {
1277 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001278 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001279 break;
1280 case LYS_IFF_AND:
1281 case LYS_IFF_OR:
1282 if (!r) {
1283 r += 2;
1284 } else {
1285 r += 1;
1286 }
1287 break;
1288 case LYS_IFF_F:
1289 f++;
1290 if (r) {
1291 r--;
1292 }
1293 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001294 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001295 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001296
Radek Krejci9ff0a922016-07-14 13:08:05 +02001297result:
1298 if (expr_size) {
1299 *expr_size = e;
1300 }
1301 if (feat_size) {
1302 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001303 }
1304}
1305
1306int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001307resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1308 struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001309{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001310 const char *c = value;
1311 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001312 int i, j, last_not, checkversion = 0;
1313 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001314 uint8_t op;
1315 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001316 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001317
Radek Krejci9ff0a922016-07-14 13:08:05 +02001318 assert(c);
1319
1320 if (isspace(c[0])) {
1321 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1322 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001323 }
1324
Radek Krejci9ff0a922016-07-14 13:08:05 +02001325 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1326 for (i = j = last_not = 0; c[i]; i++) {
1327 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001328 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001329 j++;
1330 continue;
1331 } else if (c[i] == ')') {
1332 j--;
1333 continue;
1334 } else if (isspace(c[i])) {
1335 continue;
1336 }
1337
1338 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1339 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001340 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001341 return EXIT_FAILURE;
1342 } else if (!isspace(c[i + r])) {
1343 /* feature name starting with the not/and/or */
1344 last_not = 0;
1345 f_size++;
1346 } else if (c[i] == 'n') { /* not operation */
1347 if (last_not) {
1348 /* double not */
1349 expr_size = expr_size - 2;
1350 last_not = 0;
1351 } else {
1352 last_not = 1;
1353 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001354 } else { /* and, or */
1355 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001356 /* not a not operation */
1357 last_not = 0;
1358 }
1359 i += r;
1360 } else {
1361 f_size++;
1362 last_not = 0;
1363 }
1364 expr_size++;
1365
1366 while (!isspace(c[i])) {
1367 if (!c[i] || c[i] == ')') {
1368 i--;
1369 break;
1370 }
1371 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001372 }
1373 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001374 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001375 /* not matching count of ( and ) */
1376 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1377 return EXIT_FAILURE;
1378 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001379
Radek Krejci69b8d922016-07-27 13:13:41 +02001380 if (checkversion || expr_size > 1) {
1381 /* check that we have 1.1 module */
1382 if (node->module->version != 2) {
1383 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1384 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1385 return EXIT_FAILURE;
1386 }
1387 }
1388
Radek Krejci9ff0a922016-07-14 13:08:05 +02001389 /* allocate the memory */
1390 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001391 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001392 stack.size = expr_size;
1393 stack.stack = malloc(expr_size * sizeof *stack.stack);
1394 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1395 LOGMEM;
1396 goto error;
1397 }
1398 f_size--; expr_size--; /* used as indexes from now */
1399
1400 for (i--; i >= 0; i--) {
1401 if (c[i] == ')') {
1402 /* push it on stack */
1403 iff_stack_push(&stack, LYS_IFF_RP);
1404 continue;
1405 } else if (c[i] == '(') {
1406 /* pop from the stack into result all operators until ) */
1407 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1408 iff_setop(iffeat_expr->expr, op, expr_size--);
1409 }
1410 continue;
1411 } else if (isspace(c[i])) {
1412 continue;
1413 }
1414
1415 /* end operator or operand -> find beginning and get what is it */
1416 j = i + 1;
1417 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1418 i--;
1419 }
1420 i++; /* get back by one step */
1421
1422 if (!strncmp(&c[i], "not ", 4)) {
1423 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1424 /* double not */
1425 iff_stack_pop(&stack);
1426 } else {
1427 /* not has the highest priority, so do not pop from the stack
1428 * as in case of AND and OR */
1429 iff_stack_push(&stack, LYS_IFF_NOT);
1430 }
1431 } else if (!strncmp(&c[i], "and ", 4)) {
1432 /* as for OR - pop from the stack all operators with the same or higher
1433 * priority and store them to the result, then push the AND to the stack */
1434 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1435 op = iff_stack_pop(&stack);
1436 iff_setop(iffeat_expr->expr, op, expr_size--);
1437 }
1438 iff_stack_push(&stack, LYS_IFF_AND);
1439 } else if (!strncmp(&c[i], "or ", 3)) {
1440 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1441 op = iff_stack_pop(&stack);
1442 iff_setop(iffeat_expr->expr, op, expr_size--);
1443 }
1444 iff_stack_push(&stack, LYS_IFF_OR);
1445 } else {
1446 /* feature name, length is j - i */
1447
1448 /* add it to the result */
1449 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1450
1451 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001452 * forward referenced, we have to keep the feature name in auxiliary
1453 * structure passed into unres */
1454 iff_data = malloc(sizeof *iff_data);
1455 iff_data->node = node;
1456 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1457 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1458 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001459 f_size--;
1460
1461 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001462 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001463 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001464 }
1465 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001466 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001467 while (stack.index) {
1468 op = iff_stack_pop(&stack);
1469 iff_setop(iffeat_expr->expr, op, expr_size--);
1470 }
1471
1472 if (++expr_size || ++f_size) {
1473 /* not all expected operators and operands found */
1474 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1475 rc = EXIT_FAILURE;
1476 } else {
1477 rc = EXIT_SUCCESS;
1478 }
1479
1480error:
1481 /* cleanup */
1482 iff_stack_clean(&stack);
1483
1484 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001485}
1486
1487/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001488 * @brief Resolve (find) a data node based on a schema-nodeid.
1489 *
1490 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1491 * module).
1492 *
1493 */
1494struct lyd_node *
1495resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1496{
1497 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001498 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001499 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001500 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001501
1502 assert(nodeid && start);
1503
1504 if (nodeid[0] == '/') {
1505 return NULL;
1506 }
1507
1508 str = p = strdup(nodeid);
1509 if (!str) {
1510 LOGMEM;
1511 return NULL;
1512 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001513
Michal Vasko3edeaf72016-02-11 13:17:43 +01001514 while (p) {
1515 token = p;
1516 p = strchr(p, '/');
1517 if (p) {
1518 *p = '\0';
1519 p++;
1520 }
1521
Radek Krejci5da4eb62016-04-08 14:45:51 +02001522 if (p) {
1523 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001524 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001525 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001526 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001527 result = NULL;
1528 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001529 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001530
Radek Krejci5da4eb62016-04-08 14:45:51 +02001531 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1532 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001533 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001534 /* shorthand case */
1535 if (!shorthand) {
1536 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001537 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001538 continue;
1539 } else {
1540 shorthand = 0;
1541 if (schema->nodetype == LYS_LEAF) {
1542 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1543 result = NULL;
1544 break;
1545 }
1546 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001547 }
1548 } else {
1549 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001550 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1551 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001552 || !schema) {
1553 result = NULL;
1554 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001555 }
1556 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001557 LY_TREE_FOR(result ? result->child : start, iter) {
1558 if (iter->schema == schema) {
1559 /* move in data tree according to returned schema */
1560 result = iter;
1561 break;
1562 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001563 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001564 if (!iter) {
1565 /* instance not found */
1566 result = NULL;
1567 break;
1568 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001569 }
1570 free(str);
1571
1572 return result;
1573}
1574
Radek Krejcibdf92362016-04-08 14:43:34 +02001575/*
1576 * 0 - ok (done)
1577 * 1 - continue
1578 * 2 - break
1579 * -1 - error
1580 */
1581static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001582schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001583 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001584 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001585{
1586 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001587 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001588
1589 /* module check */
1590 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001591 if (implemented_mod) {
1592 prefix_mod = lys_get_implemented_module(prefix_mod);
1593 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001594 if (!prefix_mod) {
1595 return -1;
1596 }
1597 if (prefix_mod != lys_node_module(sibling)) {
1598 return 1;
1599 }
1600
1601 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001602 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001603 if (*shorthand != -1) {
1604 *shorthand = *shorthand ? 0 : 1;
1605 }
1606 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001607 }
1608
1609 /* the result node? */
1610 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001611 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001612 return 1;
1613 }
1614 return 0;
1615 }
1616
Radek Krejcicc217a62016-04-08 16:58:11 +02001617 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001618 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001619 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001620 return -1;
1621 }
1622 *start = sibling->child;
1623 }
1624
1625 return 2;
1626}
1627
Michal Vasko3edeaf72016-02-11 13:17:43 +01001628/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1629int
1630resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1631 const struct lys_node **ret)
1632{
1633 const char *name, *mod_name, *id;
1634 const struct lys_node *sibling;
1635 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001636 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001637 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001638 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001639 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001640
1641 assert(nodeid && (start || module) && !(start && module) && ret);
1642
1643 id = nodeid;
1644
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001645 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 +01001646 return ((id - nodeid) - r) + 1;
1647 }
1648 id += r;
1649
1650 if ((is_relative && !start) || (!is_relative && !module)) {
1651 return -1;
1652 }
1653
1654 /* descendant-schema-nodeid */
1655 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001656 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001657
1658 /* absolute-schema-nodeid */
1659 } else {
1660 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001661 if (start_mod != lys_main_module(module)) {
1662 /* if the submodule augments the mainmodule (or in general a module augments
1663 * itself, we don't want to search for the implemented module but augments
1664 * the module anyway. But when augmenting another module, we need the implemented
1665 * revision of the module if any */
1666 start_mod = lys_get_implemented_module(start_mod);
1667 implemented_search = 1;
1668 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001669 if (!start_mod) {
1670 return -1;
1671 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001672 start = start_mod->data;
1673 }
1674
1675 while (1) {
1676 sibling = NULL;
1677 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1678 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1679 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001680 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001681 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1682 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001683 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001684 *ret = sibling;
1685 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001686 } else if (r == 1) {
1687 continue;
1688 } else if (r == 2) {
1689 break;
1690 } else {
1691 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001692 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001693 }
1694 }
1695
1696 /* no match */
1697 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001698 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001699 return EXIT_SUCCESS;
1700 }
1701
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001702 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 +01001703 return ((id - nodeid) - r) + 1;
1704 }
1705 id += r;
1706 }
1707
1708 /* cannot get here */
1709 LOGINT;
1710 return -1;
1711}
1712
Radek Krejcif3c71de2016-04-11 12:45:46 +02001713/* unique, refine,
1714 * >0 - unexpected char on position (ret - 1),
1715 * 0 - ok (but ret can still be NULL),
1716 * -1 - error,
1717 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001718int
1719resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001720 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001721{
1722 const char *name, *mod_name, *id;
1723 const struct lys_node *sibling;
1724 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001725 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001727 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728
1729 assert(nodeid && start && ret);
1730 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1731
1732 id = nodeid;
1733 module = start->module;
1734
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001735 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 +01001736 return ((id - nodeid) - r) + 1;
1737 }
1738 id += r;
1739
1740 if (!is_relative) {
1741 return -1;
1742 }
1743
1744 while (1) {
1745 sibling = NULL;
1746 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1747 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1748 /* name match */
1749 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001750 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001751 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001752 if (!(sibling->nodetype & ret_nodetype)) {
1753 /* wrong node type, too bad */
1754 continue;
1755 }
1756 *ret = sibling;
1757 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001758 } else if (r == 1) {
1759 continue;
1760 } else if (r == 2) {
1761 break;
1762 } else {
1763 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001764 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001765 }
1766 }
1767
1768 /* no match */
1769 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001770 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001772 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1773 *ret = NULL;
1774 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001775 }
1776
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001777 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 +01001778 return ((id - nodeid) - r) + 1;
1779 }
1780 id += r;
1781 }
1782
1783 /* cannot get here */
1784 LOGINT;
1785 return -1;
1786}
1787
1788/* choice default */
1789int
1790resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1791{
1792 /* cannot actually be a path */
1793 if (strchr(nodeid, '/')) {
1794 return -1;
1795 }
1796
Radek Krejcif3c71de2016-04-11 12:45:46 +02001797 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001798}
1799
1800/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1801static int
1802resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1803{
1804 const struct lys_module *module;
1805 const char *mod_prefix, *name;
1806 int i, mod_prefix_len, nam_len;
1807
1808 /* parse the identifier, it must be parsed on one call */
1809 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1810 return -i + 1;
1811 }
1812
1813 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1814 if (!module) {
1815 return -1;
1816 }
1817 if (module != start->module) {
1818 start = module->data;
1819 }
1820
1821 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1822
1823 return EXIT_SUCCESS;
1824}
1825
1826int
1827resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1828 const struct lys_node **ret)
1829{
1830 const char *name, *mod_name, *id;
1831 const struct lys_node *sibling, *start;
1832 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001833 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001834 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001835
1836 assert(nodeid && module && ret);
1837 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1838
1839 id = nodeid;
1840 start = module->data;
1841
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001842 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 +01001843 return ((id - nodeid) - r) + 1;
1844 }
1845 id += r;
1846
1847 if (is_relative) {
1848 return -1;
1849 }
1850
1851 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001852 if (!abs_start_mod) {
1853 return -1;
1854 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001855
1856 while (1) {
1857 sibling = NULL;
1858 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1859 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1860 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001861 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001862 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001863 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001864 if (!(sibling->nodetype & ret_nodetype)) {
1865 /* wrong node type, too bad */
1866 continue;
1867 }
1868 *ret = sibling;
1869 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001870 } else if (r == 1) {
1871 continue;
1872 } else if (r == 2) {
1873 break;
1874 } else {
1875 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001876 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001877 }
1878 }
1879
1880 /* no match */
1881 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001882 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001883 return EXIT_SUCCESS;
1884 }
1885
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001886 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 +01001887 return ((id - nodeid) - r) + 1;
1888 }
1889 id += r;
1890 }
1891
1892 /* cannot get here */
1893 LOGINT;
1894 return -1;
1895}
1896
Michal Vaskoe733d682016-03-14 09:08:27 +01001897static int
Michal Vasko3547c532016-03-14 09:40:50 +01001898resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001899{
1900 const char *name;
1901 int nam_len, has_predicate, i;
1902
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001903 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1904 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001905 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001906 return -1;
1907 }
1908
1909 predicate += i;
1910 *parsed += i;
1911
1912 for (i = 0; i < list->keys_size; ++i) {
1913 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1914 break;
1915 }
1916 }
1917
1918 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001919 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001920 return -1;
1921 }
1922
1923 /* more predicates? */
1924 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001925 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001926 }
1927
1928 return 0;
1929}
1930
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001931/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001932const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001933resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001934{
Michal Vasko10728b52016-04-07 14:26:29 +02001935 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001936 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001937 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001938 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001939 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001940 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941
Michal Vasko3547c532016-03-14 09:40:50 +01001942 assert(nodeid && (ctx || start));
1943 if (!ctx) {
1944 ctx = start->module->ctx;
1945 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001946
1947 id = nodeid;
1948
Michal Vaskoe733d682016-03-14 09:08:27 +01001949 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 +01001950 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001951 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001952 }
1953 id += r;
1954
1955 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001956 assert(start);
1957 start = start->child;
1958 if (!start) {
1959 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001960 str = strndup(nodeid, (name + nam_len) - nodeid);
1961 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1962 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001963 return NULL;
1964 }
1965 module = start->module;
1966 } else {
1967 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001968 str = strndup(nodeid, (name + nam_len) - nodeid);
1969 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1970 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001971 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001972 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1973 LOGINT;
1974 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001975 }
1976
Michal Vasko971a3ca2016-04-01 13:09:29 +02001977 if (ly_buf_used && module_name[0]) {
1978 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1979 }
1980 ly_buf_used++;
1981
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001982 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001983 module_name[mod_name_len] = '\0';
1984 module = ly_ctx_get_module(ctx, module_name, NULL);
1985
1986 if (buf_backup) {
1987 /* return previous internal buffer content */
1988 strcpy(module_name, buf_backup);
1989 free(buf_backup);
1990 buf_backup = NULL;
1991 }
1992 ly_buf_used--;
1993
Michal Vasko3547c532016-03-14 09:40:50 +01001994 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001995 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1996 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1997 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001998 return NULL;
1999 }
2000 start = module->data;
2001
2002 /* now it's as if there was no module name */
2003 mod_name = NULL;
2004 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002005 }
2006
Michal Vaskoe733d682016-03-14 09:08:27 +01002007 prev_mod = module;
2008
Michal Vasko3edeaf72016-02-11 13:17:43 +01002009 while (1) {
2010 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002011 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2012 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002013 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002014 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 /* module check */
2016 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002017 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002018 LOGINT;
2019 return NULL;
2020 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002021
2022 if (ly_buf_used && module_name[0]) {
2023 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2024 }
2025 ly_buf_used++;
2026
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002027 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002028 module_name[mod_name_len] = '\0';
2029 /* will also find an augment module */
2030 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002031
2032 if (buf_backup) {
2033 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002034 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002035 free(buf_backup);
2036 buf_backup = NULL;
2037 }
2038 ly_buf_used--;
2039
Michal Vasko3edeaf72016-02-11 13:17:43 +01002040 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002041 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2042 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2043 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002044 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002045 }
2046 } else {
2047 prefix_mod = prev_mod;
2048 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002049 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002050 continue;
2051 }
2052
Michal Vaskoe733d682016-03-14 09:08:27 +01002053 /* do we have some predicates on it? */
2054 if (has_predicate) {
2055 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002056 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2057 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2058 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2059 return NULL;
2060 }
2061 } else if (sibling->nodetype == LYS_LIST) {
2062 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2063 return NULL;
2064 }
2065 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002066 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002067 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002068 }
2069 id += r;
2070 }
2071
Radek Krejcibdf92362016-04-08 14:43:34 +02002072 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002073 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002074 shorthand = ~shorthand;
2075 }
2076
Michal Vasko3edeaf72016-02-11 13:17:43 +01002077 /* the result node? */
2078 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002079 if (shorthand) {
2080 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002081 str = strndup(nodeid, (name + nam_len) - nodeid);
2082 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002083 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002084 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002085 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002086 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002087 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002088 }
2089
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002090 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002091 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002092 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002093 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002094 return NULL;
2095 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002096 start = sibling->child;
2097 }
2098
2099 /* update prev mod */
2100 prev_mod = start->module;
2101 break;
2102 }
2103 }
2104
2105 /* no match */
2106 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002107 str = strndup(nodeid, (name + nam_len) - nodeid);
2108 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2109 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002110 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002111 }
2112
Michal Vaskoe733d682016-03-14 09:08:27 +01002113 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 +01002114 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002115 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002116 }
2117 id += r;
2118 }
2119
2120 /* cannot get here */
2121 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002122 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002123}
2124
Michal Vasko22448d32016-03-16 13:17:29 +01002125static int
2126resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2127{
2128 const char *name, *value;
2129 int nam_len, val_len, has_predicate = 1, r;
2130 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002131 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002132
Radek Krejci61a86c62016-03-24 11:06:44 +01002133 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002134 assert(node->schema->nodetype == LYS_LIST);
2135
Michal Vaskof29903d2016-04-18 13:13:10 +02002136 key = (struct lyd_node_leaf_list *)node->child;
2137 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2138 if (!key) {
2139 /* invalid data */
2140 LOGINT;
2141 return -1;
2142 }
Michal Vasko22448d32016-03-16 13:17:29 +01002143
Michal Vasko22448d32016-03-16 13:17:29 +01002144 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002145 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002146 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002147 }
2148
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002149 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2150 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002151 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002152 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002153 }
2154
2155 predicate += r;
2156 *parsed += r;
2157
Michal Vaskof29903d2016-04-18 13:13:10 +02002158 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002159 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002160 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002161 }
2162
2163 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002164 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002165 return 1;
2166 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002167
2168 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002169 }
2170
2171 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002172 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002173 return -1;
2174 }
2175
2176 return 0;
2177}
2178
Radek Krejci45826012016-08-24 15:07:57 +02002179/**
2180 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2181 *
2182 * @param[in] nodeid Node data path to find
2183 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2184 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2185 * @param[out] parsed Number of characters processed in \p id
2186 * @return The closes parent (or the node itself) from the path
2187 */
Michal Vasko22448d32016-03-16 13:17:29 +01002188struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002189resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2190 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002191{
Michal Vasko10728b52016-04-07 14:26:29 +02002192 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002193 const char *id, *mod_name, *name, *pred_name;
2194 int r, ret, mod_name_len, nam_len, is_relative = -1;
2195 int has_predicate, last_parsed, val_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002196 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002197 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002198 const struct lys_module *prefix_mod, *prev_mod;
2199 struct ly_ctx *ctx;
2200
2201 assert(nodeid && start && parsed);
2202
2203 ctx = start->schema->module->ctx;
2204 id = nodeid;
2205
2206 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 +01002207 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002208 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002209 return NULL;
2210 }
2211 id += r;
2212 /* add it to parsed only after the data node was actually found */
2213 last_parsed = r;
2214
2215 if (is_relative) {
2216 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002217 start = start->child;
2218 } else {
2219 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002220 prev_mod = start->schema->module;
2221 }
2222
2223 while (1) {
2224 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01002225 /* RPC data check, return simply invalid argument, because the data tree is invalid */
2226 if (lys_parent(sibling->schema)) {
2227 if (options & LYD_PATH_OPT_OUTPUT) {
2228 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002229 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002230 *parsed = -1;
2231 return NULL;
2232 }
2233 } else {
2234 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002235 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002236 *parsed = -1;
2237 return NULL;
2238 }
2239 }
2240 }
2241
Michal Vasko22448d32016-03-16 13:17:29 +01002242 /* name match */
2243 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2244
2245 /* module check */
2246 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002247 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002248 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002249 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002250 return NULL;
2251 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002252
2253 if (ly_buf_used && module_name[0]) {
2254 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2255 }
2256 ly_buf_used++;
2257
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002258 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002259 module_name[mod_name_len] = '\0';
2260 /* will also find an augment module */
2261 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002262
2263 if (buf_backup) {
2264 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002265 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002266 free(buf_backup);
2267 buf_backup = NULL;
2268 }
2269 ly_buf_used--;
2270
Michal Vasko22448d32016-03-16 13:17:29 +01002271 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002272 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2273 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2274 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002275 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002276 return NULL;
2277 }
2278 } else {
2279 prefix_mod = prev_mod;
2280 }
2281 if (prefix_mod != lys_node_module(sibling->schema)) {
2282 continue;
2283 }
2284
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002285 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002286 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002287 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002288 if (has_predicate) {
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002289 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &val_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002290 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2291 *parsed = -1;
2292 return NULL;
2293 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002294 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2295 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2296 *parsed = -1;
2297 return NULL;
2298 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002299 } else {
2300 r = 0;
2301 if (llist_value) {
2302 val_len = strlen(llist_value);
2303 } else {
2304 val_len = 0;
2305 }
2306 }
2307
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002308 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskof0a50972016-10-19 11:33:55 +02002309 if ((!val_len && llist->value_str && llist->value_str[0])
2310 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002311 continue;
2312 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002313 id += r;
2314 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002315 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002316
Radek Krejci45826012016-08-24 15:07:57 +02002317 } else if (sibling->schema->nodetype == LYS_LIST) {
2318 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002319 r = 0;
2320 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002321 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002322 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002323 return NULL;
2324 }
2325 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2326 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002327 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002328 return NULL;
2329 } else if (ret == 1) {
2330 /* this list instance does not match */
2331 continue;
2332 }
2333 id += r;
2334 last_parsed += r;
2335 }
2336
2337 *parsed += last_parsed;
2338
2339 /* the result node? */
2340 if (!id[0]) {
2341 return sibling;
2342 }
2343
2344 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002345 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002346 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002347 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002348 return NULL;
2349 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002350 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002351 start = sibling->child;
2352 if (start) {
2353 prev_mod = start->schema->module;
2354 }
2355 break;
2356 }
2357 }
2358
2359 /* no match, return last match */
2360 if (!sibling) {
2361 return last_match;
2362 }
2363
2364 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 +01002365 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002366 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002367 return NULL;
2368 }
2369 id += r;
2370 last_parsed = r;
2371 }
2372
2373 /* cannot get here */
2374 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002375 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002376 return NULL;
2377}
2378
Michal Vasko3edeaf72016-02-11 13:17:43 +01002379/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002380 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002381 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002382 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002383 * @param[in] str_restr Restriction as a string.
2384 * @param[in] type Type of the restriction.
2385 * @param[out] ret Final interval structure that starts with
2386 * the interval of the initial type, continues with intervals
2387 * of any superior types derived from the initial one, and
2388 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002389 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002390 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002391 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002392int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002393resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002394{
2395 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002396 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002397 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002398 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002399 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002400 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002401 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002402
2403 switch (type->base) {
2404 case LY_TYPE_BINARY:
2405 kind = 0;
2406 local_umin = 0;
2407 local_umax = 18446744073709551615UL;
2408
2409 if (!str_restr && type->info.binary.length) {
2410 str_restr = type->info.binary.length->expr;
2411 }
2412 break;
2413 case LY_TYPE_DEC64:
2414 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002415 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2416 local_fmax = __INT64_C(9223372036854775807);
2417 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002418
2419 if (!str_restr && type->info.dec64.range) {
2420 str_restr = type->info.dec64.range->expr;
2421 }
2422 break;
2423 case LY_TYPE_INT8:
2424 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002425 local_smin = __INT64_C(-128);
2426 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002427
2428 if (!str_restr && type->info.num.range) {
2429 str_restr = type->info.num.range->expr;
2430 }
2431 break;
2432 case LY_TYPE_INT16:
2433 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002434 local_smin = __INT64_C(-32768);
2435 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002436
2437 if (!str_restr && type->info.num.range) {
2438 str_restr = type->info.num.range->expr;
2439 }
2440 break;
2441 case LY_TYPE_INT32:
2442 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002443 local_smin = __INT64_C(-2147483648);
2444 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002445
2446 if (!str_restr && type->info.num.range) {
2447 str_restr = type->info.num.range->expr;
2448 }
2449 break;
2450 case LY_TYPE_INT64:
2451 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002452 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2453 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002454
2455 if (!str_restr && type->info.num.range) {
2456 str_restr = type->info.num.range->expr;
2457 }
2458 break;
2459 case LY_TYPE_UINT8:
2460 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002461 local_umin = __UINT64_C(0);
2462 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002463
2464 if (!str_restr && type->info.num.range) {
2465 str_restr = type->info.num.range->expr;
2466 }
2467 break;
2468 case LY_TYPE_UINT16:
2469 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002470 local_umin = __UINT64_C(0);
2471 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002472
2473 if (!str_restr && type->info.num.range) {
2474 str_restr = type->info.num.range->expr;
2475 }
2476 break;
2477 case LY_TYPE_UINT32:
2478 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002479 local_umin = __UINT64_C(0);
2480 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002481
2482 if (!str_restr && type->info.num.range) {
2483 str_restr = type->info.num.range->expr;
2484 }
2485 break;
2486 case LY_TYPE_UINT64:
2487 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002488 local_umin = __UINT64_C(0);
2489 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002490
2491 if (!str_restr && type->info.num.range) {
2492 str_restr = type->info.num.range->expr;
2493 }
2494 break;
2495 case LY_TYPE_STRING:
2496 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002497 local_umin = __UINT64_C(0);
2498 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002499
2500 if (!str_restr && type->info.str.length) {
2501 str_restr = type->info.str.length->expr;
2502 }
2503 break;
2504 default:
2505 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002506 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002507 }
2508
2509 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002510 if (type->der) {
2511 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002512 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002513 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002514 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002515 assert(!intv || (intv->kind == kind));
2516 }
2517
2518 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002519 /* we do not have any restriction, return superior ones */
2520 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002521 return EXIT_SUCCESS;
2522 }
2523
2524 /* adjust local min and max */
2525 if (intv) {
2526 tmp_intv = intv;
2527
2528 if (kind == 0) {
2529 local_umin = tmp_intv->value.uval.min;
2530 } else if (kind == 1) {
2531 local_smin = tmp_intv->value.sval.min;
2532 } else if (kind == 2) {
2533 local_fmin = tmp_intv->value.fval.min;
2534 }
2535
2536 while (tmp_intv->next) {
2537 tmp_intv = tmp_intv->next;
2538 }
2539
2540 if (kind == 0) {
2541 local_umax = tmp_intv->value.uval.max;
2542 } else if (kind == 1) {
2543 local_smax = tmp_intv->value.sval.max;
2544 } else if (kind == 2) {
2545 local_fmax = tmp_intv->value.fval.max;
2546 }
2547 }
2548
2549 /* finally parse our restriction */
2550 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002551 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002552 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002553 if (!tmp_local_intv) {
2554 assert(!local_intv);
2555 local_intv = malloc(sizeof *local_intv);
2556 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002557 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002558 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002559 tmp_local_intv = tmp_local_intv->next;
2560 }
Michal Vasko253035f2015-12-17 16:58:13 +01002561 if (!tmp_local_intv) {
2562 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002563 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002564 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002565
2566 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002567 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002568 tmp_local_intv->next = NULL;
2569
2570 /* min */
2571 ptr = seg_ptr;
2572 while (isspace(ptr[0])) {
2573 ++ptr;
2574 }
2575 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2576 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002577 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002578 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002579 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002580 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002581 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2582 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2583 goto error;
2584 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002585 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002586 } else if (!strncmp(ptr, "min", 3)) {
2587 if (kind == 0) {
2588 tmp_local_intv->value.uval.min = local_umin;
2589 } else if (kind == 1) {
2590 tmp_local_intv->value.sval.min = local_smin;
2591 } else if (kind == 2) {
2592 tmp_local_intv->value.fval.min = local_fmin;
2593 }
2594
2595 ptr += 3;
2596 } else if (!strncmp(ptr, "max", 3)) {
2597 if (kind == 0) {
2598 tmp_local_intv->value.uval.min = local_umax;
2599 } else if (kind == 1) {
2600 tmp_local_intv->value.sval.min = local_smax;
2601 } else if (kind == 2) {
2602 tmp_local_intv->value.fval.min = local_fmax;
2603 }
2604
2605 ptr += 3;
2606 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002607 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002608 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002609 }
2610
2611 while (isspace(ptr[0])) {
2612 ptr++;
2613 }
2614
2615 /* no interval or interval */
2616 if ((ptr[0] == '|') || !ptr[0]) {
2617 if (kind == 0) {
2618 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2619 } else if (kind == 1) {
2620 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2621 } else if (kind == 2) {
2622 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2623 }
2624 } else if (!strncmp(ptr, "..", 2)) {
2625 /* skip ".." */
2626 ptr += 2;
2627 while (isspace(ptr[0])) {
2628 ++ptr;
2629 }
2630
2631 /* max */
2632 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2633 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002634 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002635 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002636 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002637 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002638 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2639 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2640 goto error;
2641 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002642 }
2643 } else if (!strncmp(ptr, "max", 3)) {
2644 if (kind == 0) {
2645 tmp_local_intv->value.uval.max = local_umax;
2646 } else if (kind == 1) {
2647 tmp_local_intv->value.sval.max = local_smax;
2648 } else if (kind == 2) {
2649 tmp_local_intv->value.fval.max = local_fmax;
2650 }
2651 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002652 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002653 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002654 }
2655 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002656 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002657 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002658 }
2659
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002660 /* check min and max in correct order*/
2661 if (kind == 0) {
2662 /* current segment */
2663 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2664 goto error;
2665 }
2666 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2667 goto error;
2668 }
2669 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002670 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002671 goto error;
2672 }
2673 } else if (kind == 1) {
2674 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2675 goto error;
2676 }
2677 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2678 goto error;
2679 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002680 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002681 goto error;
2682 }
2683 } else if (kind == 2) {
2684 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2685 goto error;
2686 }
2687 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2688 goto error;
2689 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002690 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002691 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002692 goto error;
2693 }
2694 }
2695
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002696 /* next segment (next OR) */
2697 seg_ptr = strchr(seg_ptr, '|');
2698 if (!seg_ptr) {
2699 break;
2700 }
2701 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002702 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002703 }
2704
2705 /* check local restrictions against superior ones */
2706 if (intv) {
2707 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002708 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002709
2710 while (tmp_local_intv && tmp_intv) {
2711 /* reuse local variables */
2712 if (kind == 0) {
2713 local_umin = tmp_local_intv->value.uval.min;
2714 local_umax = tmp_local_intv->value.uval.max;
2715
2716 /* it must be in this interval */
2717 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2718 /* this interval is covered, next one */
2719 if (local_umax <= tmp_intv->value.uval.max) {
2720 tmp_local_intv = tmp_local_intv->next;
2721 continue;
2722 /* ascending order of restrictions -> fail */
2723 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002724 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002725 }
2726 }
2727 } else if (kind == 1) {
2728 local_smin = tmp_local_intv->value.sval.min;
2729 local_smax = tmp_local_intv->value.sval.max;
2730
2731 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2732 if (local_smax <= tmp_intv->value.sval.max) {
2733 tmp_local_intv = tmp_local_intv->next;
2734 continue;
2735 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002736 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002737 }
2738 }
2739 } else if (kind == 2) {
2740 local_fmin = tmp_local_intv->value.fval.min;
2741 local_fmax = tmp_local_intv->value.fval.max;
2742
Michal Vasko4d1f0482016-09-19 14:35:06 +02002743 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002744 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002745 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002746 tmp_local_intv = tmp_local_intv->next;
2747 continue;
2748 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002749 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002750 }
2751 }
2752 }
2753
2754 tmp_intv = tmp_intv->next;
2755 }
2756
2757 /* some interval left uncovered -> fail */
2758 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002759 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002760 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002761 }
2762
Michal Vaskoaeb51802016-04-11 10:58:47 +02002763 /* append the local intervals to all the intervals of the superior types, return it all */
2764 if (intv) {
2765 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2766 tmp_intv->next = local_intv;
2767 } else {
2768 intv = local_intv;
2769 }
2770 *ret = intv;
2771
2772 return EXIT_SUCCESS;
2773
2774error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002775 while (intv) {
2776 tmp_intv = intv->next;
2777 free(intv);
2778 intv = tmp_intv;
2779 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002780 while (local_intv) {
2781 tmp_local_intv = local_intv->next;
2782 free(local_intv);
2783 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002784 }
2785
Michal Vaskoaeb51802016-04-11 10:58:47 +02002786 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002787}
2788
Michal Vasko730dfdf2015-08-11 14:48:05 +02002789/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002790 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2791 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002792 *
2793 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002794 * @param[in] mod_name Typedef name module name.
2795 * @param[in] module Main module.
2796 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002797 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002798 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002799 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002800 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002801int
Michal Vasko1e62a092015-12-01 12:27:20 +01002802resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2803 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002804{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002805 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002806 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002807 int tpdf_size;
2808
Michal Vasko1dca6882015-10-22 14:29:42 +02002809 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002810 /* no prefix, try built-in types */
2811 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2812 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002813 if (ret) {
2814 *ret = ly_types[i].def;
2815 }
2816 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 }
2818 }
2819 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002820 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002821 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002822 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 }
2824 }
2825
Michal Vasko1dca6882015-10-22 14:29:42 +02002826 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002827 /* search in local typedefs */
2828 while (parent) {
2829 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002830 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002831 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2832 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002833 break;
2834
Radek Krejci76512572015-08-04 09:47:08 +02002835 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002836 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2837 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002838 break;
2839
Radek Krejci76512572015-08-04 09:47:08 +02002840 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002841 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2842 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002843 break;
2844
Radek Krejci76512572015-08-04 09:47:08 +02002845 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002846 case LYS_ACTION:
2847 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2848 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002849 break;
2850
Radek Krejci76512572015-08-04 09:47:08 +02002851 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002852 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2853 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002854 break;
2855
Radek Krejci76512572015-08-04 09:47:08 +02002856 case LYS_INPUT:
2857 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002858 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2859 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 break;
2861
2862 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002863 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002864 continue;
2865 }
2866
2867 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002868 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002869 match = &tpdf[i];
2870 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002871 }
2872 }
2873
Michal Vaskodcf98e62016-05-05 17:53:53 +02002874 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 }
Radek Krejcic071c542016-01-27 14:57:51 +01002876 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002878 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002879 if (!module) {
2880 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 }
2882 }
2883
2884 /* search in top level typedefs */
2885 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002886 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002887 match = &module->tpdf[i];
2888 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 }
2890 }
2891
2892 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002893 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002894 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002895 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 +02002896 match = &module->inc[i].submodule->tpdf[j];
2897 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 }
2899 }
2900 }
2901
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002902 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002903
2904check_leafref:
2905 if (ret) {
2906 *ret = match;
2907 }
2908 if (match->type.base == LY_TYPE_LEAFREF) {
2909 while (!match->type.info.lref.path) {
2910 match = match->type.der;
2911 assert(match);
2912 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002913 }
2914 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002915}
2916
Michal Vasko1dca6882015-10-22 14:29:42 +02002917/**
2918 * @brief Check the default \p value of the \p type. Logs directly.
2919 *
2920 * @param[in] type Type definition to use.
2921 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002922 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002923 *
2924 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2925 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002927check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928{
Radek Krejcibad2f172016-08-02 11:04:15 +02002929 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002930 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002931 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002932
Radek Krejcic13db382016-08-16 10:52:42 +02002933 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002934 /* the type was not resolved yet, nothing to do for now */
2935 return EXIT_FAILURE;
2936 }
2937
2938 if (!value) {
2939 /* we do not have a new default value, so is there any to check even, in some base type? */
2940 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2941 if (base_tpdf->dflt) {
2942 value = base_tpdf->dflt;
2943 break;
2944 }
2945 }
2946
2947 if (!value) {
2948 /* no default value, nothing to check, all is well */
2949 return EXIT_SUCCESS;
2950 }
2951
2952 /* 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)? */
2953 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002954 case LY_TYPE_IDENT:
2955 case LY_TYPE_INST:
2956 case LY_TYPE_LEAFREF:
2957 case LY_TYPE_BOOL:
2958 case LY_TYPE_EMPTY:
2959 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2960 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002961 case LY_TYPE_BITS:
2962 /* the default value must match the restricted list of values, if the type was restricted */
2963 if (type->info.bits.count) {
2964 break;
2965 }
2966 return EXIT_SUCCESS;
2967 case LY_TYPE_ENUM:
2968 /* the default value must match the restricted list of values, if the type was restricted */
2969 if (type->info.enums.count) {
2970 break;
2971 }
2972 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002973 case LY_TYPE_DEC64:
2974 if (type->info.dec64.range) {
2975 break;
2976 }
2977 return EXIT_SUCCESS;
2978 case LY_TYPE_BINARY:
2979 if (type->info.binary.length) {
2980 break;
2981 }
2982 return EXIT_SUCCESS;
2983 case LY_TYPE_INT8:
2984 case LY_TYPE_INT16:
2985 case LY_TYPE_INT32:
2986 case LY_TYPE_INT64:
2987 case LY_TYPE_UINT8:
2988 case LY_TYPE_UINT16:
2989 case LY_TYPE_UINT32:
2990 case LY_TYPE_UINT64:
2991 if (type->info.num.range) {
2992 break;
2993 }
2994 return EXIT_SUCCESS;
2995 case LY_TYPE_STRING:
2996 if (type->info.str.length || type->info.str.patterns) {
2997 break;
2998 }
2999 return EXIT_SUCCESS;
3000 case LY_TYPE_UNION:
3001 /* way too much trouble learning whether we need to check the default again, so just do it */
3002 break;
3003 default:
3004 LOGINT;
3005 return -1;
3006 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003007 } else if (type->base == LY_TYPE_EMPTY) {
3008 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3009 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3010 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003011 }
3012
Michal Vasko1dca6882015-10-22 14:29:42 +02003013 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003014 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003015 node.value_str = value;
3016 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003017 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003018 if (!node.schema) {
3019 LOGMEM;
3020 return -1;
3021 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003022 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003023 if (!node.schema->name) {
3024 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003025 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003026 return -1;
3027 }
Michal Vasko56826402016-03-02 11:11:37 +01003028 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003029 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003030
Radek Krejci37b756f2016-01-18 10:15:03 +01003031 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003032 if (!type->info.lref.target) {
3033 ret = EXIT_FAILURE;
3034 goto finish;
3035 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003036 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003037
3038 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3039 /* it was converted to JSON format before, nothing else sensible we can do */
3040
3041 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003042 if (lyp_parse_value(&node, NULL, 1)) {
3043 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003044 if (base_tpdf) {
3045 /* default value was is defined in some base typedef */
3046 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3047 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3048 /* we have refined bits/enums */
3049 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3050 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3051 value, type->parent->name, base_tpdf->name);
3052 }
3053 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003054 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003055 }
3056
3057finish:
3058 if (node.value_type == LY_TYPE_BITS) {
3059 free(node.value.bit);
3060 }
3061 free((char *)node.schema->name);
3062 free(node.schema);
3063
3064 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003065}
3066
Michal Vasko730dfdf2015-08-11 14:48:05 +02003067/**
3068 * @brief Check a key for mandatory attributes. Logs directly.
3069 *
3070 * @param[in] key The key to check.
3071 * @param[in] flags What flags to check.
3072 * @param[in] list The list of all the keys.
3073 * @param[in] index Index of the key in the key list.
3074 * @param[in] name The name of the keys.
3075 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003076 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003077 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003078 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003079static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003080check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081{
Radek Krejciadb57612016-02-16 13:34:34 +01003082 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003083 char *dup = NULL;
3084 int j;
3085
3086 /* existence */
3087 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003088 if (name[len] != '\0') {
3089 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003090 if (!dup) {
3091 LOGMEM;
3092 return -1;
3093 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003094 dup[len] = '\0';
3095 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003096 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003097 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003098 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003099 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003100 }
3101
3102 /* uniqueness */
3103 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003104 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003105 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003106 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003107 }
3108 }
3109
3110 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003111 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003112 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003113 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003114 }
3115
3116 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003117 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003118 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003119 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120 }
3121
3122 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003123 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003124 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003125 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003126 }
3127
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003128 /* key is not placed from augment */
3129 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003130 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3131 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003132 return -1;
3133 }
3134
Radek Krejci3f21ada2016-08-01 13:34:31 +02003135 /* key is not when/if-feature -conditional */
3136 j = 0;
3137 if (key->when || (key->iffeature_size && (j = 1))) {
3138 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3139 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3140 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003141 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003142 }
3143
Michal Vasko0b85aa82016-03-07 14:37:43 +01003144 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003145}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003146
3147/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003148 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003149 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003150 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003151 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152 *
3153 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3154 */
3155int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003156resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003157{
Radek Krejci581ce772015-11-10 17:22:40 +01003158 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003159 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003160
Radek Krejcif3c71de2016-04-11 12:45:46 +02003161 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003162 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003163 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003164 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003165 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003166 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003167 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003168 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003169 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003170 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003171 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003172 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3173 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003174 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175 }
Radek Krejci581ce772015-11-10 17:22:40 +01003176 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003178 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003179 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3180 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003181 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182 }
3183
Radek Krejcicf509982015-12-15 09:22:44 +01003184 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003185 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003186 return -1;
3187 }
3188
Radek Krejcid09d1a52016-08-11 14:05:45 +02003189 /* check that all unique's targets are of the same config type */
3190 if (*trg_type) {
3191 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3192 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3193 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3194 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3195 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3196 return -1;
3197 }
3198 } else {
3199 /* first unique */
3200 if (leaf->flags & LYS_CONFIG_W) {
3201 *trg_type = 1;
3202 } else {
3203 *trg_type = 2;
3204 }
3205 }
3206
Radek Krejcica7efb72016-01-18 13:06:01 +01003207 /* set leaf's unique flag */
3208 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3209
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210 return EXIT_SUCCESS;
3211
3212error:
3213
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003214 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003215}
3216
Radek Krejci0c0086a2016-03-24 15:20:28 +01003217void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003218unres_data_del(struct unres_data *unres, uint32_t i)
3219{
3220 /* there are items after the one deleted */
3221 if (i+1 < unres->count) {
3222 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003223 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003224
3225 /* deleting the last item */
3226 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003227 free(unres->node);
3228 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003229 }
3230
3231 /* if there are no items after and it is not the last one, just move the counter */
3232 --unres->count;
3233}
3234
Michal Vasko0491ab32015-08-19 14:28:29 +02003235/**
3236 * @brief Resolve (find) a data node from a specific module. Does not log.
3237 *
3238 * @param[in] mod Module to search in.
3239 * @param[in] name Name of the data node.
3240 * @param[in] nam_len Length of the name.
3241 * @param[in] start Data node to start the search from.
3242 * @param[in,out] parents Resolved nodes. If there are some parents,
3243 * they are replaced (!!) with the resolvents.
3244 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003245 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003246 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003247static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003248resolve_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 +02003249{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003251 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003252 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253
Michal Vasko23b61ec2015-08-19 11:19:50 +02003254 if (!parents->count) {
3255 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003256 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003257 if (!parents->node) {
3258 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003259 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003260 }
Michal Vaskocf024702015-10-08 15:01:42 +02003261 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003263 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003264 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003266 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 continue;
3268 }
3269 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003270 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3272 && node->schema->name[nam_len] == '\0') {
3273 /* matching target */
3274 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003275 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003276 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277 flag = 1;
3278 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003279 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003280 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003281 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3282 if (!parents->node) {
3283 return EXIT_FAILURE;
3284 }
Michal Vaskocf024702015-10-08 15:01:42 +02003285 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003286 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003287 }
3288 }
3289 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003290
3291 if (!flag) {
3292 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003293 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003294 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003295 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003296 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003297 }
3298
Michal Vasko0491ab32015-08-19 14:28:29 +02003299 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003300}
3301
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003302/**
3303 * @brief Resolve (find) a data node. Does not log.
3304 *
Radek Krejci581ce772015-11-10 17:22:40 +01003305 * @param[in] mod_name Module name of the data node.
3306 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003307 * @param[in] name Name of the data node.
3308 * @param[in] nam_len Length of the name.
3309 * @param[in] start Data node to start the search from.
3310 * @param[in,out] parents Resolved nodes. If there are some parents,
3311 * they are replaced (!!) with the resolvents.
3312 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003313 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003314 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003315static int
Radek Krejci581ce772015-11-10 17:22:40 +01003316resolve_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 +02003317 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003318{
Michal Vasko1e62a092015-12-01 12:27:20 +01003319 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003320 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003321
Michal Vasko23b61ec2015-08-19 11:19:50 +02003322 assert(start);
3323
Michal Vasko31fc3672015-10-21 12:08:13 +02003324 if (mod_name) {
3325 /* we have mod_name, find appropriate module */
3326 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003327 if (!str) {
3328 LOGMEM;
3329 return -1;
3330 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003331 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3332 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003333 if (!mod) {
3334 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003335 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003336 }
3337 } else {
3338 /* no prefix, module is the same as of current node */
3339 mod = start->schema->module;
3340 }
3341
3342 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003343}
3344
Michal Vasko730dfdf2015-08-11 14:48:05 +02003345/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003346 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003347 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003348 *
Michal Vaskobb211122015-08-19 14:03:11 +02003349 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003350 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003351 * @param[in,out] node_match Nodes satisfying the restriction
3352 * without the predicate. Nodes not
3353 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003354 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003355 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003356 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003358static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003359resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003360 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003361{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003362 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003363 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003365 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3366 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003367 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003368 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369
3370 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003371 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003372 if (!source_match.node) {
3373 LOGMEM;
3374 return -1;
3375 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003376 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003377 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003378 if (!dest_match.node) {
3379 LOGMEM;
3380 return -1;
3381 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382
3383 do {
3384 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3385 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003386 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003387 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003388 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003390 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 pred += i;
3392
Michal Vasko23b61ec2015-08-19 11:19:50 +02003393 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003394 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003395 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003396
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003397 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003398 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003399 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003400 i = 0;
3401 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
3403
3404 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003405 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003406 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3408 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003409 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003410 rc = -1;
3411 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003413 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003414 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003415 dest_match.node[0] = dest_match.node[0]->parent;
3416 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003417 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003418 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003419 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003420 }
3421 }
3422 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003423 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003424 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003425 i = 0;
3426 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 }
3428
3429 if (pke_len == pke_parsed) {
3430 break;
3431 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003432 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 +02003433 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003434 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003435 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003436 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003437 }
3438 pke_parsed += i;
3439 }
3440
3441 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003442 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3443 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3444 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3445 }
3446 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3447 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3448 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3449 }
3450 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003451 goto remove_leafref;
3452 }
3453
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003454 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003455 goto remove_leafref;
3456 }
3457
3458 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003459 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460 continue;
3461
3462remove_leafref:
3463 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003464 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 }
3466 } while (has_predicate);
3467
Michal Vaskocf024702015-10-08 15:01:42 +02003468 free(source_match.node);
3469 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003470 if (parsed) {
3471 *parsed = parsed_loc;
3472 }
3473 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003474
3475error:
3476
3477 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003478 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003479 }
3480 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003481 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003482 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003483 if (parsed) {
3484 *parsed = -parsed_loc+i;
3485 }
3486 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003487}
3488
Michal Vasko730dfdf2015-08-11 14:48:05 +02003489/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003490 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003491 *
Michal Vaskocf024702015-10-08 15:01:42 +02003492 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003493 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003494 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003495 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003496 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003497 */
Michal Vasko184521f2015-09-24 13:14:26 +02003498static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003499resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003500{
Radek Krejci71b795b2015-08-10 16:20:39 +02003501 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003503 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003504 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003505
Michal Vaskocf024702015-10-08 15:01:42 +02003506 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003507
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003509 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510
3511 /* searching for nodeset */
3512 do {
3513 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003514 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003515 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 goto error;
3517 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003519 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520
Michal Vasko23b61ec2015-08-19 11:19:50 +02003521 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003522 if (parent_times > 0) {
3523 data = node;
3524 for (i = 1; i < parent_times; ++i) {
3525 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003526 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003527 } else if (!parent_times) {
3528 data = node->child;
3529 } else {
3530 /* absolute path */
3531 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 }
3533
Michal Vaskobfd98e62016-09-02 09:50:05 +02003534 /* we may still be parsing it and the pointer is not correct yet */
3535 if (data->prev) {
3536 while (data->prev->next) {
3537 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003538 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003539 }
3540 }
3541
3542 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003543 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003544 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003545 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003546 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547 goto error;
3548 }
3549
3550 if (has_predicate) {
3551 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003552 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003553 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3554 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003556 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557 continue;
3558 }
3559
3560 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003561 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003562 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003563 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003564 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003565 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003566 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 goto error;
3568 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003570 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003571
Michal Vasko23b61ec2015-08-19 11:19:50 +02003572 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003573 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003574 goto error;
3575 }
3576 }
3577 } while (path[0] != '\0');
3578
Michal Vaskof02e3742015-08-05 16:27:02 +02003579 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003580
3581error:
3582
Michal Vaskocf024702015-10-08 15:01:42 +02003583 free(ret->node);
3584 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003585 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586
Michal Vasko0491ab32015-08-19 14:28:29 +02003587 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588}
3589
Michal Vaskoe27516a2016-10-10 17:55:31 +00003590static int
3591resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3592{
3593 int dep1, dep2;
3594 const struct lys_node *node;
3595
3596 if (lys_parent(op_node)) {
3597 /* inner operation (notif/action) */
3598 if (abs_path) {
3599 return 1;
3600 } else {
3601 /* compare depth of both nodes */
3602 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3603 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3604 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3605 return 1;
3606 }
3607 }
3608 } else {
3609 /* top-level operation (notif/rpc) */
3610 if (op_node != first_node) {
3611 return 1;
3612 }
3613 }
3614
3615 return 0;
3616}
3617
Michal Vasko730dfdf2015-08-11 14:48:05 +02003618/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003619 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003620 *
Michal Vaskobb211122015-08-19 14:03:11 +02003621 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003622 * @param[in] context_node Predicate context node (where the predicate is placed).
3623 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003624 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003625 *
Michal Vasko184521f2015-09-24 13:14:26 +02003626 * @return 0 on forward reference, otherwise the number
3627 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003628 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003629 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003630static int
Radek Krejciadb57612016-02-16 13:34:34 +01003631resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003632 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003633{
Michal Vasko1e62a092015-12-01 12:27:20 +01003634 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003635 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003636 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3637 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003638
3639 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003640 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003641 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003642 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003643 return -parsed+i;
3644 }
3645 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003646 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003647
Michal Vasko58090902015-08-13 14:04:15 +02003648 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003649 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003650 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003651 }
Radek Krejciadb57612016-02-16 13:34:34 +01003652 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003653 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003655 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003656 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003657 }
3658
3659 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003660 dest_parent_times = 0;
3661 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003662 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3663 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003664 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 +02003665 return -parsed;
3666 }
3667 pke_parsed += i;
3668
Radek Krejciadb57612016-02-16 13:34:34 +01003669 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003670 /* path is supposed to be evaluated in data tree, so we have to skip
3671 * all schema nodes that cannot be instantiated in data tree */
3672 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003673 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003674 dst_node = lys_parent(dst_node));
3675
Michal Vasko1f76a282015-08-04 16:16:53 +02003676 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003677 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003678 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003679 }
3680 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003681 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003682 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003683 if (!dest_pref) {
3684 dest_pref = dst_node->module->name;
3685 }
3686 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003687 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003688 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003689 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003690 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003691 }
3692
Michal Vaskoe27516a2016-10-10 17:55:31 +00003693 if (first_iter) {
3694 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3695 parent->flags |= LYS_VALID_DEP;
3696 }
3697 first_iter = 0;
3698 }
3699
Michal Vasko1f76a282015-08-04 16:16:53 +02003700 if (pke_len == pke_parsed) {
3701 break;
3702 }
3703
3704 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3705 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003706 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003707 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003708 return -parsed;
3709 }
3710 pke_parsed += i;
3711 }
3712
3713 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003714 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003715 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003716 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3717 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003718 return -parsed;
3719 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003720 } while (has_predicate);
3721
3722 return parsed;
3723}
3724
Michal Vasko730dfdf2015-08-11 14:48:05 +02003725/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003726 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003727 *
Michal Vaskobb211122015-08-19 14:03:11 +02003728 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003730 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3731 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003732 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003733 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003734 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003736static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003737resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003738 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003739{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003740 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003741 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003742 const char *id, *prefix, *name;
3743 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003744 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003745
Michal Vasko184521f2015-09-24 13:14:26 +02003746 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003747 parent_times = 0;
3748 id = path;
3749
Michal Vaskoe27516a2016-10-10 17:55:31 +00003750 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003751 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003752 for (op_node = lys_parent(parent);
3753 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3754 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003755 }
3756
Radek Krejci27fe55e2016-09-13 17:13:35 +02003757 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003758 do {
3759 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003760 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 +02003761 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003762 }
3763 id += i;
3764
Michal Vasko184521f2015-09-24 13:14:26 +02003765 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003766 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003767 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003768 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003769 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003770 /* get start node */
3771 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003772 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003773 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3774 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003775 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003776 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003777 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003778 if (parent_tpdf) {
3779 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003780 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003781 return -1;
3782 }
3783
Michal Vasko94458082016-10-07 14:34:36 +02003784 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3785 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003786 /* path is supposed to be evaluated in data tree, so we have to skip
3787 * all schema nodes that cannot be instantiated in data tree */
3788 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003789 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003790 node = lys_parent(node));
3791
Michal Vasko1f76a282015-08-04 16:16:53 +02003792 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003793 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003794 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003795 }
3796 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003797 } else {
3798 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003799 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003800 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003801 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003802 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003803 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003804 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 +01003805 return -1;
3806 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003807 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003808 if (!node) {
3809 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3810 "leafref", path);
3811 return EXIT_FAILURE;
3812 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003813 }
3814
Michal Vasko4f0dad02016-02-15 14:08:23 +01003815 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003816 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003817 }
3818
Michal Vasko36cbaa42015-12-14 13:15:48 +01003819 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 +02003820 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003821 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003822 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003823 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003824
Michal Vaskoe27516a2016-10-10 17:55:31 +00003825 if (first_iter) {
3826 /* set external dependency flag, we can decide based on the first found node */
3827 if (!parent_tpdf && op_node && parent_times &&
3828 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3829 parent->flags |= LYS_VALID_DEP;
3830 }
3831 first_iter = 0;
3832 }
3833
Michal Vasko1f76a282015-08-04 16:16:53 +02003834 if (has_predicate) {
3835 /* we have predicate, so the current result must be list */
3836 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003837 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003838 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003839 }
3840
Michal Vaskoe27516a2016-10-10 17:55:31 +00003841 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003842 if (i <= 0) {
3843 if (i == 0) {
3844 return EXIT_FAILURE;
3845 } else { /* i < 0 */
3846 return -1;
3847 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003848 }
3849 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003850 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003851 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003852 mod = lys_node_module(node);
3853 if (!mod->implemented && mod != mod2) {
3854 /* set the module implemented */
3855 if (lys_set_implemented(mod)) {
3856 return -1;
3857 }
3858 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003859 } while (id[0]);
3860
Michal Vaskoca917682016-07-25 11:00:37 +02003861 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3862 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003863 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003864 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3865 "Leafref target \"%s\" is not a leaf%s.", path,
3866 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003867 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003868 }
3869
Radek Krejcicf509982015-12-15 09:22:44 +01003870 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003871 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003872 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003873 return -1;
3874 }
3875
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003876 if (ret) {
3877 *ret = node;
3878 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003879
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003880 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003881}
3882
Michal Vasko730dfdf2015-08-11 14:48:05 +02003883/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003884 * @brief Resolve instance-identifier predicate in JSON data format.
3885 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003886 *
Michal Vaskobb211122015-08-19 14:03:11 +02003887 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003888 * @param[in,out] node_match Nodes matching the restriction without
3889 * the predicate. Nodes not satisfying
3890 * the predicate are removed.
3891 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003892 * @return Number of characters successfully parsed,
3893 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003894 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003895static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003896resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003897{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003898 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003899 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003900 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003901 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003902 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003903
Michal Vasko1f2cc332015-08-19 11:18:32 +02003904 assert(pred && node_match->count);
3905
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003906 idx = -1;
3907 parsed = 0;
3908
Michal Vaskob2f40be2016-09-08 16:03:48 +02003909 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003910 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003911 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912 return -parsed+i;
3913 }
3914 parsed += i;
3915 pred += i;
3916
3917 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003918 /* pos */
3919 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003920 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003921 } else if (name[0] != '.') {
3922 /* list keys */
3923 if (pred_iter < 0) {
3924 pred_iter = 1;
3925 } else {
3926 ++pred_iter;
3927 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003928 }
3929
Michal Vaskof2f28a12016-09-09 12:43:06 +02003930 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003931 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003932 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003933 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003934 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003935 goto remove_instid;
3936 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003937
3938 target = node_match->node[j];
3939 /* check the value */
3940 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3941 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3942 goto remove_instid;
3943 }
3944
3945 } else if (!value) {
3946 /* keyless list position */
3947 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3948 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3949 goto remove_instid;
3950 }
3951
3952 if (idx != cur_idx) {
3953 goto remove_instid;
3954 }
3955
3956 } else {
3957 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003958 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003959 goto remove_instid;
3960 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003961
3962 /* key module must match the list module */
3963 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3964 || node_match->node[j]->schema->module->name[mod_len]) {
3965 goto remove_instid;
3966 }
3967 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003968 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003969 if (!target) {
3970 goto remove_instid;
3971 }
3972 if ((struct lys_node_leaf *)target->schema !=
3973 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3974 goto remove_instid;
3975 }
3976
3977 /* check the value */
3978 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3979 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3980 goto remove_instid;
3981 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003982 }
3983
Michal Vaskob2f40be2016-09-08 16:03:48 +02003984 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003985 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003986 continue;
3987
3988remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003989 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003990 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003991 }
3992 } while (has_predicate);
3993
Michal Vaskob2f40be2016-09-08 16:03:48 +02003994 /* check that all list keys were specified */
3995 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003996 j = 0;
3997 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003998 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
3999 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4000 /* not enough predicates, just remove the list instance */
4001 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004002 } else {
4003 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004004 }
4005 }
4006
4007 if (!node_match->count) {
4008 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4009 }
4010 }
4011
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004012 return parsed;
4013}
4014
Michal Vasko730dfdf2015-08-11 14:48:05 +02004015/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004016 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004017 *
Radek Krejciadb57612016-02-16 13:34:34 +01004018 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004019 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004020 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004021 * @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 +02004022 */
Michal Vasko184521f2015-09-24 13:14:26 +02004023static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004024resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004025{
Radek Krejcic5090c32015-08-12 09:46:19 +02004026 int i = 0, j;
4027 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004028 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004029 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004030 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004031 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004032 int mod_len, name_len, has_predicate;
4033 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004034
4035 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036
Radek Krejcic5090c32015-08-12 09:46:19 +02004037 /* we need root to resolve absolute path */
4038 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004039 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004040 if (data->prev) {
4041 for (; data->prev->next; data = data->prev);
4042 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004043
Radek Krejcic5090c32015-08-12 09:46:19 +02004044 /* search for the instance node */
4045 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004046 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004047 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004048 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049 goto error;
4050 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004051 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004052
Michal Vaskob2f40be2016-09-08 16:03:48 +02004053 str = strndup(model, mod_len);
4054 if (!str) {
4055 LOGMEM;
4056 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004057 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004058 mod = ly_ctx_get_module(ctx, str, NULL);
4059 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004060
Michal Vasko1f2cc332015-08-19 11:18:32 +02004061 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004062 /* no instance exists */
4063 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064 }
4065
4066 if (has_predicate) {
4067 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004068 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004069 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004070 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004071 goto error;
4072 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004073 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004074
Michal Vasko1f2cc332015-08-19 11:18:32 +02004075 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004076 /* no instance exists */
4077 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004078 }
4079 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080 }
4081
Michal Vasko1f2cc332015-08-19 11:18:32 +02004082 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004083 /* no instance exists */
4084 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004085 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004086 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004087 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004088 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004089 } else {
4090 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004091 result = node_match.node[0];
4092 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004093 return result;
4094 }
4095
4096error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004097 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004098 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004099 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004100}
4101
Michal Vasko730dfdf2015-08-11 14:48:05 +02004102/**
Michal Vasko9e635ac2016-10-17 11:44:09 +02004103 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
4104 *
4105 * @param[in] node Node to examine.
4106 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4107 */
4108static int
4109check_node_xpath(struct lys_node *node)
4110{
4111 struct lys_node *parent, *elem;
4112 struct lyxp_set set;
4113 uint32_t i;
4114 int rc;
4115
4116 parent = node;
4117 while (parent) {
4118 if (parent->nodetype == LYS_GROUPING) {
4119 /* unresolved grouping, skip for now (will be checked later) */
4120 return EXIT_SUCCESS;
4121 }
4122 if (parent->nodetype == LYS_AUGMENT) {
4123 if (!((struct lys_node_augment *)parent)->target) {
4124 /* uresolved augment, skip for now (will be checked later) */
4125 return EXIT_SUCCESS;
4126 } else {
4127 parent = ((struct lys_node_augment *)parent)->target;
4128 continue;
4129 }
4130 }
4131 parent = parent->parent;
4132 }
4133
4134 rc = lyxp_node_atomize(node, &set);
4135 if (rc) {
4136 return rc;
4137 }
4138
4139 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4140
4141 for (i = 0; i < set.used; ++i) {
4142 /* skip roots'n'stuff */
4143 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4144 /* XPath expression cannot reference "lower" status than the node that has the definition */
4145 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4146 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4147 return -1;
4148 }
4149
4150 if (parent) {
4151 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4152 if (!elem) {
4153 /* not in node's RPC or notification subtree, set the flag */
4154 node->flags |= LYS_VALID_DEP;
4155 break;
4156 }
4157 }
4158 }
4159 }
4160
4161 free(set.val.snodes);
4162 return EXIT_SUCCESS;
4163}
4164
4165/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004166 * @brief Passes config flag down to children, skips nodes without config flags.
4167 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004168 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004169 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004170 * @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 +02004171 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004172 *
4173 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004174 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004175static int
Michal Vasko9e635ac2016-10-17 11:44:09 +02004176inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list, int check_xpath)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004177{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004178 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004179 LY_TREE_FOR(node, node) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004180 if (check_xpath && check_node_xpath(node)) {
4181 return -1;
4182 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004183 if (clear) {
4184 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004185 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004186 } else {
4187 if (node->flags & LYS_CONFIG_SET) {
4188 /* skip nodes with an explicit config value */
4189 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4190 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4191 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4192 return -1;
4193 }
4194 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004195 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004196
4197 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4198 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4199 /* check that configuration lists have keys */
4200 if (check_list && (node->nodetype == LYS_LIST)
4201 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4202 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4203 return -1;
4204 }
4205 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004206 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004207 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004208 if (inherit_config_flag(node->child, flags, clear, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004209 return -1;
4210 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004212 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004213
4214 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004215}
4216
Michal Vasko730dfdf2015-08-11 14:48:05 +02004217/**
Michal Vasko7178e692016-02-12 15:58:05 +01004218 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004219 *
Michal Vaskobb211122015-08-19 14:03:11 +02004220 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004221 * @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 +02004222 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004223 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004224 */
Michal Vasko7178e692016-02-12 15:58:05 +01004225static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004226resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004227{
Michal Vaskoe022a562016-09-27 14:24:15 +02004228 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004229 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004230 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004231 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004232
Michal Vasko15b36692016-08-26 15:29:54 +02004233 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004234
Michal Vasko15b36692016-08-26 15:29:54 +02004235 /* resolve target node */
4236 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4237 if (rc == -1) {
4238 return -1;
4239 }
4240 if (rc > 0) {
4241 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4242 return -1;
4243 }
4244 if (!aug_target) {
4245 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4246 return EXIT_FAILURE;
4247 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004248
Radek Krejci27fe55e2016-09-13 17:13:35 +02004249 /* check that we want to connect augment into its target */
4250 mod = lys_main_module(aug->module);
4251 if (!mod->implemented) {
4252 /* it must be augment only to the same module,
4253 * otherwise we do not apply augment in not-implemented
4254 * module. If the module is set to be implemented in future,
4255 * the augment is being resolved and checked again */
4256 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4257 if (lys_node_module(sub) != mod) {
4258 /* this is not an implemented module and the augment
4259 * target some other module, so avoid its connecting
4260 * to the target */
4261 return EXIT_SUCCESS;
4262 }
4263 }
4264 }
4265
Michal Vasko15b36692016-08-26 15:29:54 +02004266 if (!aug->child) {
4267 /* nothing to do */
4268 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004269 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004270 }
4271
Michal Vaskod58d5962016-03-02 14:29:41 +01004272 /* check for mandatory nodes - if the target node is in another module
4273 * the added nodes cannot be mandatory
4274 */
Michal Vasko15b36692016-08-26 15:29:54 +02004275 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004276 && (rc = lyp_check_mandatory_augment(aug))) {
4277 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004278 }
4279
Michal Vasko07e89ef2016-03-03 13:28:57 +01004280 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004281 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004282 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004283 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004284 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4285 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004286 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004287 return -1;
4288 }
4289 }
Michal Vasko15b36692016-08-26 15:29:54 +02004290 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004291 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004292 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004293 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4294 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004295 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004296 return -1;
4297 }
4298 }
4299 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004300 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004301 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004302 return -1;
4303 }
4304
Radek Krejcic071c542016-01-27 14:57:51 +01004305 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004306 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004307 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004308 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004309 }
4310 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004311
Michal Vasko15b36692016-08-26 15:29:54 +02004312 /* finally reconnect augmenting data into the target - add them to the target child list,
4313 * by setting aug->target we know the augment is fully resolved now */
4314 aug->target = (struct lys_node *)aug_target;
4315 if (aug->target->child) {
4316 sub = aug->target->child->prev; /* remember current target's last node */
4317 sub->next = aug->child; /* connect augmenting data after target's last node */
4318 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4319 aug->child->prev = sub; /* finish connecting of both child lists */
4320 } else {
4321 aug->target->child = aug->child;
4322 }
4323
Michal Vasko9e635ac2016-10-17 11:44:09 +02004324 /* inherit config information from actual parent */
4325 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4326 clear_config = (parent) ? 1 : 0;
4327 LY_TREE_FOR(aug->child, sub) {
4328 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1, 1)) {
4329 return -1;
4330 }
4331 }
4332
Radek Krejci27fe55e2016-09-13 17:13:35 +02004333success:
4334 if (mod->implemented) {
4335 /* make target modules also implemented */
4336 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4337 if (lys_set_implemented(sub->module)) {
4338 return -1;
4339 }
4340 }
4341 }
4342
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004343 return EXIT_SUCCESS;
4344}
4345
Michal Vasko730dfdf2015-08-11 14:48:05 +02004346/**
Pavol Vican855ca622016-09-05 13:07:54 +02004347 * @brief Resolve (find) choice default case. Does not log.
4348 *
4349 * @param[in] choic Choice to use.
4350 * @param[in] dflt Name of the default case.
4351 *
4352 * @return Pointer to the default node or NULL.
4353 */
4354static struct lys_node *
4355resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4356{
4357 struct lys_node *child, *ret;
4358
4359 LY_TREE_FOR(choic->child, child) {
4360 if (child->nodetype == LYS_USES) {
4361 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4362 if (ret) {
4363 return ret;
4364 }
4365 }
4366
4367 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004368 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004369 return child;
4370 }
4371 }
4372
4373 return NULL;
4374}
4375
4376/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004377 * @brief Resolve uses, apply augments, refines. Logs directly.
4378 *
Michal Vaskobb211122015-08-19 14:03:11 +02004379 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004380 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004381 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004382 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004383 */
Michal Vasko184521f2015-09-24 13:14:26 +02004384static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004385resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004386{
4387 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004388 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004389 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004390 struct lys_node_leaflist *llist;
4391 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004392 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004393 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004394 struct lys_iffeature *iff, **old_iff;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004395 int i, j, k, rc, parent_config, clear_config, check_list, check_xpath;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004396 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004397 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004398
Michal Vasko71e1aa82015-08-12 12:17:51 +02004399 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004400 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004401 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004402
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004403 if (!uses->grp->child) {
4404 /* grouping without children, warning was already displayed */
4405 return EXIT_SUCCESS;
4406 }
4407
4408 /* get proper parent (config) flags */
4409 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4410 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004411 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004412 } else {
4413 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004414 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004415 }
4416
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004417 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004418 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004419 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004420 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004421 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4422 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004423 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004424 }
Pavol Vican55abd332016-07-12 15:54:49 +02004425 /* test the name of siblings */
4426 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004427 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004428 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004429 }
4430 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004431 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004432
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004433 ctx = uses->module->ctx;
Michal Vasko4bc590c2016-09-30 12:19:51 +02004434
4435 parent = node;
4436 while (parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING))) {
4437 if (parent->nodetype == LYS_AUGMENT) {
4438 if (!((struct lys_node_augment *)parent)->target) {
4439 break;
4440 } else {
4441 parent = ((struct lys_node_augment *)parent)->target;
4442 }
4443 } else {
4444 parent = parent->parent;
4445 }
4446 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004447 if (parent) {
Michal Vasko4bc590c2016-09-30 12:19:51 +02004448 if (parent->nodetype & (LYS_GROUPING | LYS_AUGMENT)) {
4449 /* we are still in some other unresolved grouping or augment, unable to check lists */
Michal Vaskoe022a562016-09-27 14:24:15 +02004450 check_list = 0;
4451 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004452 check_xpath = 0;
Michal Vaskoe022a562016-09-27 14:24:15 +02004453 } else {
4454 check_list = 0;
4455 clear_config = 1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004456 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004457 }
4458 } else {
4459 check_list = 1;
4460 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004461 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004462 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004463
Michal Vaskoa86508c2016-08-26 14:30:19 +02004464 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004465 assert(uses->child);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004466 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004467 goto fail;
4468 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004469 }
4470
Michal Vaskodef0db12015-10-07 13:22:48 +02004471 /* we managed to copy the grouping, the rest must be possible to resolve */
4472
Pavol Vican855ca622016-09-05 13:07:54 +02004473 if (uses->refine_size) {
4474 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4475 if (!refine_nodes) {
4476 LOGMEM;
4477 goto fail;
4478 }
4479 }
4480
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004481 /* apply refines */
4482 for (i = 0; i < uses->refine_size; i++) {
4483 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004484 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004485 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004486 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004487 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004488 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004489 }
4490
Radek Krejci1d82ef62015-08-07 14:44:40 +02004491 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004492 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4493 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004494 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004495 }
Pavol Vican855ca622016-09-05 13:07:54 +02004496 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004497
4498 /* description on any nodetype */
4499 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004500 lydict_remove(ctx, node->dsc);
4501 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004502 }
4503
4504 /* reference on any nodetype */
4505 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004506 lydict_remove(ctx, node->ref);
4507 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004508 }
4509
4510 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004511 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004512 node->flags &= ~LYS_CONFIG_MASK;
4513 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004514 }
4515
4516 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004517 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004518 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004519 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004520 leaf = (struct lys_node_leaf *)node;
4521
4522 lydict_remove(ctx, leaf->dflt);
4523 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4524
4525 /* check the default value */
4526 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004527 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004528 }
Radek Krejci200bf712016-08-16 17:11:04 +02004529 } else if (node->nodetype == LYS_LEAFLIST) {
4530 /* leaf-list */
4531 llist = (struct lys_node_leaflist *)node;
4532
4533 /* remove complete set of defaults in target */
4534 for (i = 0; i < llist->dflt_size; i++) {
4535 lydict_remove(ctx, llist->dflt[i]);
4536 }
4537 free(llist->dflt);
4538
4539 /* copy the default set from refine */
4540 llist->dflt_size = rfn->dflt_size;
4541 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4542 for (i = 0; i < llist->dflt_size; i++) {
4543 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4544 }
4545
4546 /* check default value */
4547 for (i = 0; i < llist->dflt_size; i++) {
4548 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004549 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004550 }
4551 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004552 }
4553 }
4554
4555 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004556 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004557 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004558 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004559 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004560
4561 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004562 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004563 }
Pavol Vican855ca622016-09-05 13:07:54 +02004564 if (rfn->flags & LYS_MAND_TRUE) {
4565 /* check if node has default value */
4566 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4567 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4568 goto fail;
4569 }
4570 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4571 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4572 goto fail;
4573 }
4574 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004575 }
4576
4577 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004578 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4579 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4580 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004581 }
4582
4583 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004584 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004585 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004586 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004588 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004589 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004590 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004591 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004592 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004593 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004594 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004595 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004596 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004597 }
4598 }
4599
4600 /* must in leaf, leaf-list, list, container or anyxml */
4601 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004602 switch (node->nodetype) {
4603 case LYS_LEAF:
4604 old_size = &((struct lys_node_leaf *)node)->must_size;
4605 old_must = &((struct lys_node_leaf *)node)->must;
4606 break;
4607 case LYS_LEAFLIST:
4608 old_size = &((struct lys_node_leaflist *)node)->must_size;
4609 old_must = &((struct lys_node_leaflist *)node)->must;
4610 break;
4611 case LYS_LIST:
4612 old_size = &((struct lys_node_list *)node)->must_size;
4613 old_must = &((struct lys_node_list *)node)->must;
4614 break;
4615 case LYS_CONTAINER:
4616 old_size = &((struct lys_node_container *)node)->must_size;
4617 old_must = &((struct lys_node_container *)node)->must;
4618 break;
4619 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004620 case LYS_ANYDATA:
4621 old_size = &((struct lys_node_anydata *)node)->must_size;
4622 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004623 break;
4624 default:
4625 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004626 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004627 }
4628
4629 size = *old_size + rfn->must_size;
4630 must = realloc(*old_must, size * sizeof *rfn->must);
4631 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004632 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004633 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004634 }
Pavol Vican855ca622016-09-05 13:07:54 +02004635 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4636 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4637 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4638 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4639 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4640 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004641 }
4642
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004643 *old_must = must;
4644 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004645
4646 /* check XPath dependencies again */
4647 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4648 goto fail;
4649 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004650 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004651
4652 /* if-feature in leaf, leaf-list, list, container or anyxml */
4653 if (rfn->iffeature_size) {
4654 old_size = &node->iffeature_size;
4655 old_iff = &node->iffeature;
4656
4657 size = *old_size + rfn->iffeature_size;
4658 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4659 if (!iff) {
4660 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004661 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004662 }
Pavol Vican855ca622016-09-05 13:07:54 +02004663 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4664 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004665 if (usize1) {
4666 /* there is something to duplicate */
4667 /* duplicate compiled expression */
4668 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4669 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004670 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004671
4672 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004673 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4674 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004675 }
4676 }
4677
4678 *old_iff = iff;
4679 *old_size = size;
4680 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004681 }
4682
4683 /* apply augments */
4684 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004685 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004686 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004687 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004688 }
4689 }
4690
Pavol Vican855ca622016-09-05 13:07:54 +02004691 /* check refines */
4692 for (i = 0; i < uses->refine_size; i++) {
4693 node = refine_nodes[i];
4694 rfn = &uses->refine[i];
4695
4696 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004697 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004698 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4699 if (parent && parent->nodetype != LYS_GROUPING &&
4700 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4701 (rfn->flags & LYS_CONFIG_W)) {
4702 /* setting config true under config false is prohibited */
4703 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4704 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4705 "changing config from 'false' to 'true' is prohibited while "
4706 "the target's parent is still config 'false'.");
4707 goto fail;
4708 }
4709
4710 /* inherit config change to the target children */
4711 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4712 if (rfn->flags & LYS_CONFIG_W) {
4713 if (iter->flags & LYS_CONFIG_SET) {
4714 /* config is set explicitely, go to next sibling */
4715 next = NULL;
4716 goto nextsibling;
4717 }
4718 } else { /* LYS_CONFIG_R */
4719 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4720 /* error - we would have config data under status data */
4721 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4722 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4723 "changing config from 'true' to 'false' is prohibited while the target "
4724 "has still a children with explicit config 'true'.");
4725 goto fail;
4726 }
4727 }
4728 /* change config */
4729 iter->flags &= ~LYS_CONFIG_MASK;
4730 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4731
4732 /* select next iter - modified LY_TREE_DFS_END */
4733 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4734 next = NULL;
4735 } else {
4736 next = iter->child;
4737 }
4738nextsibling:
4739 if (!next) {
4740 /* try siblings */
4741 next = iter->next;
4742 }
4743 while (!next) {
4744 /* parent is already processed, go to its sibling */
4745 iter = lys_parent(iter);
4746
4747 /* no siblings, go back through parents */
4748 if (iter == node) {
4749 /* we are done, no next element to process */
4750 break;
4751 }
4752 next = iter->next;
4753 }
4754 }
4755 }
4756
4757 /* default value */
4758 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4759 /* choice */
4760
4761 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4762 rfn->dflt[0]);
4763 if (!((struct lys_node_choice *)node)->dflt) {
4764 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4765 goto fail;
4766 }
4767 if (lyp_check_mandatory_choice(node)) {
4768 goto fail;
4769 }
4770 }
4771
4772 /* min/max-elements on list or leaf-list */
4773 if (node->nodetype == LYS_LIST) {
4774 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4775 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4776 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4777 goto fail;
4778 }
4779 } else if (node->nodetype == LYS_LEAFLIST) {
4780 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4781 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4782 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4783 goto fail;
4784 }
4785 }
4786
4787 /* additional checks */
4788 if (node->nodetype == LYS_LEAFLIST) {
4789 llist = (struct lys_node_leaflist *)node;
4790 if (llist->dflt_size && llist->min) {
4791 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4792 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4793 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4794 goto fail;
4795 }
4796 }
4797 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4798 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4799 for (parent = node->parent;
4800 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4801 parent = parent->parent) {
4802 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4803 /* stop also on presence containers */
4804 break;
4805 }
4806 }
4807 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4808 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4809 if (lyp_check_mandatory_choice(parent)) {
4810 goto fail;
4811 }
4812 }
4813 }
4814 }
4815 free(refine_nodes);
4816
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004817 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004818
4819fail:
4820 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4821 lys_node_free(iter, NULL, 0);
4822 }
Pavol Vican855ca622016-09-05 13:07:54 +02004823 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004824 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004825}
4826
Radek Krejci018f1f52016-08-03 16:01:20 +02004827static int
4828identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4829{
4830 int i;
4831
4832 assert(der && base);
4833
4834 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4835 if (!base->der) {
4836 LOGMEM;
4837 return EXIT_FAILURE;
4838 }
4839 base->der[base->der_size++] = der;
4840
4841 for (i = 0; i < base->base_size; i++) {
4842 if (identity_backlink_update(der, base->base[i])) {
4843 return EXIT_FAILURE;
4844 }
4845 }
4846
4847 return EXIT_SUCCESS;
4848}
4849
Michal Vasko730dfdf2015-08-11 14:48:05 +02004850/**
4851 * @brief Resolve base identity recursively. Does not log.
4852 *
4853 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004854 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004855 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004856 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004857 *
Radek Krejci219fa612016-08-15 10:36:51 +02004858 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004859 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004860static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004861resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004862 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004863{
Michal Vaskof02e3742015-08-05 16:27:02 +02004864 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004865 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004866
Radek Krejcicf509982015-12-15 09:22:44 +01004867 assert(ret);
4868
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004869 /* search module */
4870 for (i = 0; i < module->ident_size; i++) {
4871 if (!strcmp(basename, module->ident[i].name)) {
4872
4873 if (!ident) {
4874 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004875 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004876 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004877 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004878 }
4879
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004880 base = &module->ident[i];
4881 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004882 }
4883 }
4884
4885 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004886 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4887 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4888 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004889
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004890 if (!ident) {
4891 *ret = &module->inc[j].submodule->ident[i];
4892 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004893 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004894
4895 base = &module->inc[j].submodule->ident[i];
4896 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004897 }
4898 }
4899 }
4900
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004901matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004902 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004903 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004904 /* is it already completely resolved? */
4905 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004906 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004907 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4908
4909 /* simple check for circular reference,
4910 * the complete check is done as a side effect of using only completely
4911 * resolved identities (previous check of unres content) */
4912 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4913 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4914 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004915 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004916 }
4917
Radek Krejci06f64ed2016-08-15 11:07:44 +02004918 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004919 }
4920 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004921
Radek Krejcibabbff82016-02-19 13:31:37 +01004922 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004923 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004924 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004925 }
4926
Radek Krejci219fa612016-08-15 10:36:51 +02004927 /* base not found (maybe a forward reference) */
4928 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004929}
4930
Michal Vasko730dfdf2015-08-11 14:48:05 +02004931/**
4932 * @brief Resolve base identity. Logs directly.
4933 *
4934 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004935 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004936 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004937 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004938 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004939 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004940 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004941 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004942static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004943resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004944 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004945{
4946 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004947 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004948 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004949 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004950 struct lys_module *mod;
4951
4952 assert((ident && !type) || (!ident && type));
4953
4954 if (!type) {
4955 /* have ident to resolve */
4956 ret = &target;
4957 flags = ident->flags;
4958 mod = ident->module;
4959 } else {
4960 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004961 ++type->info.ident.count;
4962 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4963 if (!type->info.ident.ref) {
4964 LOGMEM;
4965 return -1;
4966 }
4967
4968 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004969 flags = type->parent->flags;
4970 mod = type->parent->module;
4971 }
Michal Vaskof2006002016-04-21 16:28:15 +02004972 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004973
4974 /* search for the base identity */
4975 name = strchr(basename, ':');
4976 if (name) {
4977 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004978 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004979 name++;
4980
Michal Vasko2d851a92015-10-20 16:16:36 +02004981 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004982 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004983 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004984 }
4985 } else {
4986 name = basename;
4987 }
4988
Radek Krejcic071c542016-01-27 14:57:51 +01004989 /* get module where to search */
4990 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4991 if (!module) {
4992 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004993 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004994 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004995 }
4996
Radek Krejcic071c542016-01-27 14:57:51 +01004997 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004998 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4999 if (!rc) {
5000 assert(*ret);
5001
5002 /* check status */
5003 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5004 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5005 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005006 } else {
5007 if (ident) {
5008 ident->base[ident->base_size++] = *ret;
5009
5010 /* maintain backlinks to the derived identities */
5011 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5012 }
Radek Krejci219fa612016-08-15 10:36:51 +02005013 }
5014 } else if (rc == EXIT_FAILURE) {
5015 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005016 if (type) {
5017 --type->info.ident.count;
5018 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005019 }
5020
Radek Krejci219fa612016-08-15 10:36:51 +02005021 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005022}
5023
Michal Vasko730dfdf2015-08-11 14:48:05 +02005024/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005025 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005026 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005027 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005028 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005029 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005030 *
5031 * @return Pointer to the identity resolvent, NULL on error.
5032 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005033struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005034resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005035{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005036 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02005037 int mod_name_len, rc, i, j;
5038 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005039
Michal Vaskof2d43962016-09-02 11:10:16 +02005040 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005041 return NULL;
5042 }
5043
Michal Vaskoc633ca02015-08-21 14:03:51 +02005044 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005045 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005046 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005047 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005048 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005049 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005050 return NULL;
5051 }
5052
Michal Vaskof2d43962016-09-02 11:10:16 +02005053 /* go through all the bases in all the derived types */
5054 while (type->der) {
5055 for (i = 0; i < type->info.ident.count; ++i) {
5056 cur = type->info.ident.ref[i];
5057 if (!strcmp(cur->name, name) && (!mod_name
5058 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5059 goto match;
5060 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005061
Michal Vaskof2d43962016-09-02 11:10:16 +02005062 for (j = 0; j < cur->der_size; j++) {
5063 der = cur->der[j]; /* shortcut */
5064 if (!strcmp(der->name, name) &&
5065 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5066 /* we have match */
5067 cur = der;
5068 goto match;
5069 }
5070 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005071 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005072 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005073 }
5074
Radek Krejci48464ed2016-03-17 15:44:09 +01005075 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005076 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005077
5078match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005079 for (i = 0; i < cur->iffeature_size; i++) {
5080 if (!resolve_iffeature(&cur->iffeature[i])) {
5081 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005082 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005083 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005084 return NULL;
5085 }
5086 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005087 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005088}
5089
Michal Vasko730dfdf2015-08-11 14:48:05 +02005090/**
Michal Vaskobb211122015-08-19 14:03:11 +02005091 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005092 *
Michal Vaskobb211122015-08-19 14:03:11 +02005093 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005094 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005095 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005096 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005097 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005098static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005099resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005100{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005101 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005102 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005103
Radek Krejci010e54b2016-03-15 09:40:34 +01005104 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5105 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5106 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5107 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5108 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005109 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 +02005110
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005111 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005112 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5113 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005114 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005115 return -1;
5116 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005117 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005118 return -1;
5119 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005120 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005121 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5122 * (and smaller flags - it uses only a limited set of flags)
5123 */
5124 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005125 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005126 }
Michal Vasko92981a62016-10-14 10:25:16 +02005127 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005128 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005129 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005130 }
5131
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005132 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005133 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005134 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005135 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005136 } else {
5137 /* instantiate grouping only when it is completely resolved */
5138 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005139 }
Michal Vasko92981a62016-10-14 10:25:16 +02005140 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005141 return EXIT_FAILURE;
5142 }
5143
Radek Krejci48464ed2016-03-17 15:44:09 +01005144 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005145 if (!rc) {
5146 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005147 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005148 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005149 LOGINT;
5150 return -1;
5151 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005152 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005153 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005154 }
Radek Krejcicf509982015-12-15 09:22:44 +01005155
5156 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005157 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005158 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005159 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005160 return -1;
5161 }
5162
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005163 return EXIT_SUCCESS;
5164 }
5165
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005166 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005167}
5168
Michal Vasko730dfdf2015-08-11 14:48:05 +02005169/**
Michal Vasko9957e592015-08-17 15:04:09 +02005170 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005171 *
Michal Vaskobb211122015-08-19 14:03:11 +02005172 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005173 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005174 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005175 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005176 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005177static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005178resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005179{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005180 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005181 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005182
5183 for (i = 0; i < list->keys_size; ++i) {
5184 /* get the key name */
5185 if ((value = strpbrk(keys_str, " \t\n"))) {
5186 len = value - keys_str;
5187 while (isspace(value[0])) {
5188 value++;
5189 }
5190 } else {
5191 len = strlen(keys_str);
5192 }
5193
Radek Krejcic4283442016-04-22 09:19:27 +02005194 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 +02005195 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005196 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5197 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005198 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005199
Radek Krejci48464ed2016-03-17 15:44:09 +01005200 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005201 /* check_key logs */
5202 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005203 }
5204
Radek Krejcicf509982015-12-15 09:22:44 +01005205 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005206 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005207 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5208 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005209 return -1;
5210 }
5211
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212 /* prepare for next iteration */
5213 while (value && isspace(value[0])) {
5214 value++;
5215 }
5216 keys_str = value;
5217 }
5218
Michal Vaskof02e3742015-08-05 16:27:02 +02005219 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005220}
5221
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005222/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005223 * @brief Resolve (check) all must conditions of \p node.
5224 * Logs directly.
5225 *
5226 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005227 * @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 +02005228 *
5229 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5230 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005231static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005232resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005233{
Michal Vaskobf19d252015-10-08 15:39:17 +02005234 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005235 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005236 struct lys_restr *must;
5237 struct lyxp_set set;
5238
5239 assert(node);
5240 memset(&set, 0, sizeof set);
5241
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005242 if (inout_parent) {
5243 for (schema = lys_parent(node->schema);
5244 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5245 schema = lys_parent(schema));
5246 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5247 LOGINT;
5248 return -1;
5249 }
5250 must_size = ((struct lys_node_inout *)schema)->must_size;
5251 must = ((struct lys_node_inout *)schema)->must;
5252
5253 /* context node is the RPC/action */
5254 node = node->parent;
5255 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5256 LOGINT;
5257 return -1;
5258 }
5259 } else {
5260 switch (node->schema->nodetype) {
5261 case LYS_CONTAINER:
5262 must_size = ((struct lys_node_container *)node->schema)->must_size;
5263 must = ((struct lys_node_container *)node->schema)->must;
5264 break;
5265 case LYS_LEAF:
5266 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5267 must = ((struct lys_node_leaf *)node->schema)->must;
5268 break;
5269 case LYS_LEAFLIST:
5270 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5271 must = ((struct lys_node_leaflist *)node->schema)->must;
5272 break;
5273 case LYS_LIST:
5274 must_size = ((struct lys_node_list *)node->schema)->must_size;
5275 must = ((struct lys_node_list *)node->schema)->must;
5276 break;
5277 case LYS_ANYXML:
5278 case LYS_ANYDATA:
5279 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5280 must = ((struct lys_node_anydata *)node->schema)->must;
5281 break;
5282 case LYS_NOTIF:
5283 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5284 must = ((struct lys_node_notif *)node->schema)->must;
5285 break;
5286 default:
5287 must_size = 0;
5288 break;
5289 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005290 }
5291
5292 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005293 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005294 return -1;
5295 }
5296
Michal Vasko944a5642016-03-21 11:48:58 +01005297 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005298
Michal Vasko8146d4c2016-05-09 15:50:29 +02005299 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005300 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5301 if (must[i].emsg) {
5302 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5303 }
5304 if (must[i].eapptag) {
5305 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5306 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005307 return 1;
5308 }
5309 }
5310
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005311 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005312}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005313
Michal Vaskobf19d252015-10-08 15:39:17 +02005314/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005315 * @brief Resolve (find) when condition schema context node. Does not log.
5316 *
5317 * @param[in] schema Schema node with the when condition.
5318 * @param[out] ctx_snode When schema context node.
5319 * @param[out] ctx_snode_type Schema context node type.
5320 */
5321void
5322resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5323{
5324 const struct lys_node *sparent;
5325
5326 /* find a not schema-only node */
5327 *ctx_snode_type = LYXP_NODE_ELEM;
5328 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5329 if (schema->nodetype == LYS_AUGMENT) {
5330 sparent = ((struct lys_node_augment *)schema)->target;
5331 } else {
5332 sparent = schema->parent;
5333 }
5334 if (!sparent) {
5335 /* context node is the document root (fake root in our case) */
5336 if (schema->flags & LYS_CONFIG_W) {
5337 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5338 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005339 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005340 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005341 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005342 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005343 break;
5344 }
5345 schema = sparent;
5346 }
5347
5348 *ctx_snode = (struct lys_node *)schema;
5349}
5350
5351/**
Michal Vaskocf024702015-10-08 15:01:42 +02005352 * @brief Resolve (find) when condition context node. Does not log.
5353 *
5354 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005355 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005356 * @param[out] ctx_node Context node.
5357 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005358 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005359 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005360 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005361static int
5362resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5363 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005364{
Michal Vaskocf024702015-10-08 15:01:42 +02005365 struct lyd_node *parent;
5366 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005367 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005368 uint16_t i, data_depth, schema_depth;
5369
Michal Vasko508a50d2016-09-07 14:50:33 +02005370 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005371
Michal Vaskofe989752016-09-08 08:47:26 +02005372 if (node_type == LYXP_NODE_ELEM) {
5373 /* standard element context node */
5374 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5375 for (sparent = schema, schema_depth = 0;
5376 sparent;
5377 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5378 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5379 ++schema_depth;
5380 }
Michal Vaskocf024702015-10-08 15:01:42 +02005381 }
Michal Vaskofe989752016-09-08 08:47:26 +02005382 if (data_depth < schema_depth) {
5383 return -1;
5384 }
Michal Vaskocf024702015-10-08 15:01:42 +02005385
Michal Vasko956e8542016-08-26 09:43:35 +02005386 /* find the corresponding data node */
5387 for (i = 0; i < data_depth - schema_depth; ++i) {
5388 node = node->parent;
5389 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005390 if (node->schema != schema) {
5391 return -1;
5392 }
Michal Vaskofe989752016-09-08 08:47:26 +02005393 } else {
5394 /* root context node */
5395 while (node->parent) {
5396 node = node->parent;
5397 }
5398 while (node->prev->next) {
5399 node = node->prev;
5400 }
Michal Vaskocf024702015-10-08 15:01:42 +02005401 }
5402
Michal Vaskoa59495d2016-08-22 09:18:58 +02005403 *ctx_node = node;
5404 *ctx_node_type = node_type;
5405 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005406}
5407
Michal Vasko76c3bd32016-08-24 16:02:52 +02005408/**
5409 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5410 * The context nodes is adjusted if needed.
5411 *
5412 * @param[in] snode Schema node, whose children instances need to be unlinked.
5413 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5414 * it is moved to point to another sibling still in the original tree.
5415 * @param[in,out] ctx_node When context node, adjusted if needed.
5416 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5417 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5418 * Ordering may change, but there will be no semantic change.
5419 *
5420 * @return EXIT_SUCCESS on success, -1 on error.
5421 */
5422static int
5423resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5424 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5425{
5426 struct lyd_node *next, *elem;
5427
5428 switch (snode->nodetype) {
5429 case LYS_AUGMENT:
5430 case LYS_USES:
5431 case LYS_CHOICE:
5432 case LYS_CASE:
5433 LY_TREE_FOR(snode->child, snode) {
5434 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5435 return -1;
5436 }
5437 }
5438 break;
5439 case LYS_CONTAINER:
5440 case LYS_LIST:
5441 case LYS_LEAF:
5442 case LYS_LEAFLIST:
5443 case LYS_ANYXML:
5444 case LYS_ANYDATA:
5445 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5446 if (elem->schema == snode) {
5447
5448 if (elem == *ctx_node) {
5449 /* We are going to unlink our context node! This normally cannot happen,
5450 * but we use normal top-level data nodes for faking a document root node,
5451 * so if this is the context node, we just use the next top-level node.
5452 * Additionally, it can even happen that there are no top-level data nodes left,
5453 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5454 * lyxp_eval() can handle this special situation.
5455 */
5456 if (ctx_node_type == LYXP_NODE_ELEM) {
5457 LOGINT;
5458 return -1;
5459 }
5460
5461 if (elem->prev == elem) {
5462 /* unlinking last top-level element, use an empty data tree */
5463 *ctx_node = NULL;
5464 } else {
5465 /* in this case just use the previous/last top-level data node */
5466 *ctx_node = elem->prev;
5467 }
5468 } else if (elem == *node) {
5469 /* We are going to unlink the currently processed node. This does not matter that
5470 * much, but we would lose access to the original data tree, so just move our
5471 * pointer somewhere still inside it.
5472 */
5473 if ((*node)->prev != *node) {
5474 *node = (*node)->prev;
5475 } else {
5476 /* the processed node with sibings were all unlinked, oh well */
5477 *node = NULL;
5478 }
5479 }
5480
5481 /* temporarily unlink the node */
5482 lyd_unlink(elem);
5483 if (*unlinked_nodes) {
5484 if (lyd_insert_after(*unlinked_nodes, elem)) {
5485 LOGINT;
5486 return -1;
5487 }
5488 } else {
5489 *unlinked_nodes = elem;
5490 }
5491
5492 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5493 /* there can be only one instance */
5494 break;
5495 }
5496 }
5497 }
5498 break;
5499 default:
5500 LOGINT;
5501 return -1;
5502 }
5503
5504 return EXIT_SUCCESS;
5505}
5506
5507/**
5508 * @brief Relink the unlinked nodes back.
5509 *
5510 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5511 * we simply need a sibling from the original data tree.
5512 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5513 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5514 * or the sibling of \p unlinked_nodes.
5515 *
5516 * @return EXIT_SUCCESS on success, -1 on error.
5517 */
5518static int
5519resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5520{
5521 struct lyd_node *elem;
5522
5523 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5524 if (ctx_node_type == LYXP_NODE_ELEM) {
5525 if (lyd_insert(node, elem)) {
5526 return -1;
5527 }
5528 } else {
5529 if (lyd_insert_after(node, elem)) {
5530 return -1;
5531 }
5532 }
5533 }
5534
5535 return EXIT_SUCCESS;
5536}
5537
Radek Krejci03b71f72016-03-16 11:10:09 +01005538int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005539resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005540{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005541 int ret = 0;
5542 uint8_t must_size;
5543 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005544
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005545 assert(node);
5546
5547 schema = node->schema;
5548
5549 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005550 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005551 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005552 must_size = ((struct lys_node_container *)schema)->must_size;
5553 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005554 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005555 must_size = ((struct lys_node_leaf *)schema)->must_size;
5556 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005557 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005558 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5559 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005560 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005561 must_size = ((struct lys_node_list *)schema)->must_size;
5562 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005563 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005564 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005565 must_size = ((struct lys_node_anydata *)schema)->must_size;
5566 break;
5567 case LYS_NOTIF:
5568 must_size = ((struct lys_node_notif *)schema)->must_size;
5569 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005570 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005571 must_size = 0;
5572 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005573 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005574
5575 if (must_size) {
5576 ++ret;
5577 }
5578
5579 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5580 if (!node->prev->next) {
5581 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5582 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5583 ret += 0x2;
5584 }
5585 }
5586
5587 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005588}
5589
5590int
Radek Krejci46165822016-08-26 14:06:27 +02005591resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005592{
Radek Krejci46165822016-08-26 14:06:27 +02005593 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005594
Radek Krejci46165822016-08-26 14:06:27 +02005595 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005596
Radek Krejci46165822016-08-26 14:06:27 +02005597 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005598 return 1;
5599 }
5600
Radek Krejci46165822016-08-26 14:06:27 +02005601 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005602 goto check_augment;
5603
Radek Krejci46165822016-08-26 14:06:27 +02005604 while (parent) {
5605 /* stop conditions */
5606 if (!mode) {
5607 /* stop on node that can be instantiated in data tree */
5608 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5609 break;
5610 }
5611 } else {
5612 /* stop on the specified node */
5613 if (parent == stop) {
5614 break;
5615 }
5616 }
5617
5618 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005619 return 1;
5620 }
5621check_augment:
5622
5623 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005624 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005625 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005626 }
5627 parent = lys_parent(parent);
5628 }
5629
5630 return 0;
5631}
5632
Michal Vaskocf024702015-10-08 15:01:42 +02005633/**
5634 * @brief Resolve (check) all when conditions relevant for \p node.
5635 * Logs directly.
5636 *
5637 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005638 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005639 * @return
5640 * -1 - error, ly_errno is set
5641 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005642 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005643 * 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 +02005644 */
Radek Krejci46165822016-08-26 14:06:27 +02005645int
5646resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005647{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005648 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005649 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005650 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005651 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005652 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005653
5654 assert(node);
5655 memset(&set, 0, sizeof set);
5656
5657 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005658 /* make the node dummy for the evaluation */
5659 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005660 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 +02005661 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005662 if (rc) {
5663 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005664 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005665 }
Radek Krejci51093642016-03-29 10:14:59 +02005666 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005667 }
5668
Radek Krejci03b71f72016-03-16 11:10:09 +01005669 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005670 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005671 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005672 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005673 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005674 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005675 }
Radek Krejci51093642016-03-29 10:14:59 +02005676
5677 /* free xpath set content */
5678 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005679 }
5680
Michal Vasko90fc2a32016-08-24 15:58:58 +02005681 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005682 goto check_augment;
5683
5684 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005685 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5686 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005687 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005688 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005689 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005690 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005691 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005692 }
5693 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005694
5695 unlinked_nodes = NULL;
5696 /* we do not want our node pointer to change */
5697 tmp_node = node;
5698 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5699 if (rc) {
5700 goto cleanup;
5701 }
5702
5703 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5704
5705 if (unlinked_nodes && ctx_node) {
5706 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5707 rc = -1;
5708 goto cleanup;
5709 }
5710 }
5711
Radek Krejci03b71f72016-03-16 11:10:09 +01005712 if (rc) {
5713 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005714 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005715 }
Radek Krejci51093642016-03-29 10:14:59 +02005716 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005717 }
5718
Michal Vasko944a5642016-03-21 11:48:58 +01005719 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005720 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005721 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005722 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005723 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005724 }
Radek Krejci51093642016-03-29 10:14:59 +02005725
5726 /* free xpath set content */
5727 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005728 }
5729
5730check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005731 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005732 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005733 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005734 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005735 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005736 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005737 }
5738 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005739
5740 unlinked_nodes = NULL;
5741 tmp_node = node;
5742 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5743 if (rc) {
5744 goto cleanup;
5745 }
5746
5747 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5748
5749 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5750 * so the tree did not actually change and there is nothing for us to do
5751 */
5752 if (unlinked_nodes && ctx_node) {
5753 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5754 rc = -1;
5755 goto cleanup;
5756 }
5757 }
5758
Radek Krejci03b71f72016-03-16 11:10:09 +01005759 if (rc) {
5760 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005761 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005762 }
Radek Krejci51093642016-03-29 10:14:59 +02005763 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005764 }
5765
Michal Vasko944a5642016-03-21 11:48:58 +01005766 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005767
Michal Vasko8146d4c2016-05-09 15:50:29 +02005768 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005769 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005770 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005771 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005772 }
Radek Krejci51093642016-03-29 10:14:59 +02005773
5774 /* free xpath set content */
5775 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005776 }
5777
Michal Vasko90fc2a32016-08-24 15:58:58 +02005778 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005779 }
5780
Radek Krejci0b7704f2016-03-18 12:16:14 +01005781 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005782
Radek Krejci51093642016-03-29 10:14:59 +02005783cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005784 /* free xpath set content */
5785 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5786
Radek Krejci46165822016-08-26 14:06:27 +02005787 if (result) {
5788 if (node->when_status & LYD_WHEN_TRUE) {
5789 *result = 1;
5790 } else {
5791 *result = 0;
5792 }
5793 }
5794
Radek Krejci51093642016-03-29 10:14:59 +02005795 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005796}
5797
Radek Krejcicbb473e2016-09-16 14:48:32 +02005798static int
5799check_leafref_features(struct lys_type *type)
5800{
5801 struct lys_node *iter;
5802 struct ly_set *src_parents, *trg_parents, *features;
5803 unsigned int i, j, size, x;
5804 int ret = EXIT_SUCCESS;
5805
5806 assert(type->parent);
5807
5808 src_parents = ly_set_new();
5809 trg_parents = ly_set_new();
5810 features = ly_set_new();
5811
5812 /* get parents chain of source (leafref) */
5813 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5814 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5815 continue;
5816 }
5817 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5818 }
5819 /* get parents chain of target */
5820 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5821 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5822 continue;
5823 }
5824 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5825 }
5826
5827 /* compare the features used in if-feature statements in the rest of both
5828 * chains of parents. The set of features used for target must be a subset
5829 * of features used for the leafref. This is not a perfect, we should compare
5830 * the truth tables but it could require too much resources, so we simplify that */
5831 for (i = 0; i < src_parents->number; i++) {
5832 iter = src_parents->set.s[i]; /* shortcut */
5833 if (!iter->iffeature_size) {
5834 continue;
5835 }
5836 for (j = 0; j < iter->iffeature_size; j++) {
5837 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5838 for (; size; size--) {
5839 if (!iter->iffeature[j].features[size - 1]) {
5840 /* not yet resolved feature, postpone this check */
5841 ret = EXIT_FAILURE;
5842 goto cleanup;
5843 }
5844 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5845 }
5846 }
5847 }
5848 x = features->number;
5849 for (i = 0; i < trg_parents->number; i++) {
5850 iter = trg_parents->set.s[i]; /* shortcut */
5851 if (!iter->iffeature_size) {
5852 continue;
5853 }
5854 for (j = 0; j < iter->iffeature_size; j++) {
5855 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5856 for (; size; size--) {
5857 if (!iter->iffeature[j].features[size - 1]) {
5858 /* not yet resolved feature, postpone this check */
5859 ret = EXIT_FAILURE;
5860 goto cleanup;
5861 }
5862 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5863 /* the feature is not present in features set of target's parents chain */
5864 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5865 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5866 "Leafref is not conditional based on \"%s\" feature as its target.",
5867 iter->iffeature[j].features[size - 1]->name);
5868 ret = -1;
5869 goto cleanup;
5870 }
5871 }
5872 }
5873 }
5874
5875cleanup:
5876 ly_set_free(features);
5877 ly_set_free(src_parents);
5878 ly_set_free(trg_parents);
5879
5880 return ret;
5881}
5882
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005883/**
Michal Vaskobb211122015-08-19 14:03:11 +02005884 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005885 *
5886 * @param[in] mod Main module.
5887 * @param[in] item Item to resolve. Type determined by \p type.
5888 * @param[in] type Type of the unresolved item.
5889 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005890 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005891 *
5892 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5893 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005894static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005895resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005896 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005897{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005898 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005899 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5900 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005901 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005902 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005903
Radek Krejcic79c6b12016-07-26 15:11:49 +02005904 struct ly_set *refs, *procs;
5905 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005906 struct lys_ident *ident;
5907 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005908 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005909 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005910 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005911 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005912 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005913
5914 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005915 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005916 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005917 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005918 ident = item;
5919
Radek Krejci018f1f52016-08-03 16:01:20 +02005920 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005921 break;
5922 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005923 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005924 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005925 stype = item;
5926
Radek Krejci018f1f52016-08-03 16:01:20 +02005927 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005928 break;
5929 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005930 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005931 stype = item;
5932
Radek Krejci2f12f852016-01-08 12:59:57 +01005933 /* HACK - when there is no parent, we are in top level typedef and in that
5934 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5935 * know it via tpdf_flag */
5936 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005937 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005938 node = (struct lys_node *)stype->parent;
5939 }
5940
Radek Krejci27fe55e2016-09-13 17:13:35 +02005941 if (!lys_node_module(node)->implemented) {
5942 /* not implemented module, don't bother with resolving the leafref
5943 * if the module is set to be implemented, tha path will be resolved then */
5944 rc = 0;
5945 break;
5946 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005947 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005948 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005949 if (!tpdf_flag && !rc) {
5950 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005951 /* check if leafref and its target are under a common if-features */
5952 rc = check_leafref_features(stype);
5953 if (rc) {
5954 break;
5955 }
5956
Radek Krejci46c4cd72016-01-21 15:13:52 +01005957 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005958 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5959 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005960 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005961 }
5962
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005963 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005964 case UNRES_TYPE_DER_TPDF:
5965 tpdf_flag = 1;
5966 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005967 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005968 /* parent */
5969 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005970 stype = item;
5971
Michal Vasko88c29542015-11-27 14:57:53 +01005972 /* HACK type->der is temporarily unparsed type statement */
5973 yin = (struct lyxml_elem *)stype->der;
5974 stype->der = NULL;
5975
Pavol Vicana0e4e672016-02-24 12:20:04 +01005976 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5977 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005978 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005979
5980 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005981 /* may try again later */
5982 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005983 } else {
5984 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005985 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005986 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005987 }
5988
Michal Vasko88c29542015-11-27 14:57:53 +01005989 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005990 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005991 if (!rc) {
5992 /* we need to always be able to free this, it's safe only in this case */
5993 lyxml_free(mod->ctx, yin);
5994 } else {
5995 /* may try again later, put all back how it was */
5996 stype->der = (struct lys_tpdf *)yin;
5997 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005998 }
Radek Krejcic13db382016-08-16 10:52:42 +02005999 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006000 /* it does not make sense to have leaf-list of empty type */
6001 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6002 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6003 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006004 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006005 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6006 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6007 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6008 * 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 +02006009 * 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 +02006010 * of the type's base member. */
6011 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6012 if (par_grp) {
6013 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006014 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006015 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006016 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006017 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006018 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006019 iff_data = str_snode;
6020 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006021 if (!rc) {
6022 /* success */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006023 lydict_remove(mod->ctx, iff_data->fname);
6024 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006025 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006026 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006027 case UNRES_FEATURE:
6028 feat = (struct lys_feature *)item;
6029
6030 if (feat->iffeature_size) {
6031 refs = ly_set_new();
6032 procs = ly_set_new();
6033 ly_set_add(procs, feat, 0);
6034
6035 while (procs->number) {
6036 ref = procs->set.g[procs->number - 1];
6037 ly_set_rm_index(procs, procs->number - 1);
6038
6039 for (i = 0; i < ref->iffeature_size; i++) {
6040 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6041 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006042 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006043 if (ref->iffeature[i].features[j - 1] == feat) {
6044 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6045 goto featurecheckdone;
6046 }
6047
6048 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6049 k = refs->number;
6050 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6051 /* not yet seen feature, add it for processing */
6052 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6053 }
6054 }
6055 } else {
6056 /* forward reference */
6057 rc = EXIT_FAILURE;
6058 goto featurecheckdone;
6059 }
6060 }
6061
6062 }
6063 }
6064 rc = EXIT_SUCCESS;
6065
6066featurecheckdone:
6067 ly_set_free(refs);
6068 ly_set_free(procs);
6069 }
6070
6071 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006072 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006073 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006074 break;
6075 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006076 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006077 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006078 stype = item;
6079
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006080 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006081 break;
6082 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006083 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006084 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006085 choic = item;
6086
Radek Krejcie00d2312016-08-12 15:27:49 +02006087 if (!choic->dflt) {
6088 choic->dflt = resolve_choice_dflt(choic, expr);
6089 }
Michal Vasko7955b362015-09-04 14:18:15 +02006090 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006091 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006092 } else {
6093 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006094 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006095 break;
6096 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006097 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006098 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006099 break;
6100 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006101 unique_info = (struct unres_list_uniq *)item;
6102 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006103 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006104 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006105 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006106 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006107 case UNRES_XPATH:
6108 node = (struct lys_node *)item;
Michal Vasko9e635ac2016-10-17 11:44:09 +02006109 rc = check_node_xpath(node);
Michal Vasko508a50d2016-09-07 14:50:33 +02006110 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006111 default:
6112 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006113 break;
6114 }
6115
Radek Krejci54081ce2016-08-12 15:21:47 +02006116 if (has_str && !rc) {
6117 /* the string is no more needed in case of success.
6118 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006119 lydict_remove(mod->ctx, str_snode);
6120 }
6121
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006122 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006123}
6124
Michal Vaskof02e3742015-08-05 16:27:02 +02006125/* logs directly */
6126static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006127print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006128{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006129 struct lyxml_elem *xml;
6130 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006131 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006132 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006133
Michal Vaskof02e3742015-08-05 16:27:02 +02006134 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006135 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006136 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006137 break;
6138 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006139 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006140 break;
6141 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006142 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6143 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006144 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006145 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006146 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006147 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6148 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6149 type_name = ((struct yang_type *)xml)->name;
6150 } else {
6151 LY_TREE_FOR(xml->attr, attr) {
6152 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6153 type_name = attr->value;
6154 break;
6155 }
6156 }
6157 assert(attr);
6158 }
6159 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006160 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006161 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006162 iff_data = str_node;
6163 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006164 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006165 case UNRES_FEATURE:
6166 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6167 ((struct lys_feature *)item)->name);
6168 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006169 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006170 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006171 break;
6172 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006173 if (str_node) {
6174 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6175 } /* else no default value in the type itself, but we are checking some restrictions against
6176 * possible default value of some base type. The failure is caused by not resolved base type,
6177 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006178 break;
6179 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006180 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006181 break;
6182 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006183 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006184 break;
6185 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006186 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006187 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006188 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006189 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6190 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006191 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006192 case UNRES_XPATH:
6193 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6194 (char *)str_node, ((struct lys_node *)item)->name);
6195 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006196 default:
6197 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006198 break;
6199 }
6200}
6201
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006202/**
Michal Vaskobb211122015-08-19 14:03:11 +02006203 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006204 *
6205 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006206 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006207 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006208 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006209 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006210int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006211resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006212{
Radek Krejci010e54b2016-03-15 09:40:34 +01006213 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006214 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006215
6216 assert(unres);
6217
Michal Vaskoe8734262016-09-29 14:12:06 +02006218 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006219 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006220
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006221 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006222 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006223 unres_count = 0;
6224 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006225
6226 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006227 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006228 * if-features are resolved here to make sure that we will have all if-features for
6229 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006230 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006231 continue;
6232 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006233 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006234 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006235
Michal Vasko88c29542015-11-27 14:57:53 +01006236 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006237 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006238 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006239 unres->type[i] = UNRES_RESOLVED;
6240 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006241 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006242 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006243 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006244 /* print the error */
6245 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006246 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006247 } else {
6248 /* forward reference, erase ly_errno */
6249 ly_errno = LY_SUCCESS;
6250 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006251 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006252 }
Michal Vasko88c29542015-11-27 14:57:53 +01006253 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006254
Michal Vasko88c29542015-11-27 14:57:53 +01006255 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006256 /* just print the errors */
6257 ly_vlog_hide(0);
6258
6259 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006260 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006261 continue;
6262 }
6263 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6264 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006265 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006266 }
6267
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006268 /* the rest */
6269 for (i = 0; i < unres->count; ++i) {
6270 if (unres->type[i] == UNRES_RESOLVED) {
6271 continue;
6272 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006273
Radek Krejci48464ed2016-03-17 15:44:09 +01006274 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006275 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006276 if (unres->type[i] == UNRES_LIST_UNIQ) {
6277 /* free the allocated structure */
6278 free(unres->item[i]);
6279 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006280 unres->type[i] = UNRES_RESOLVED;
6281 ++resolved;
6282 } else if (rc == -1) {
6283 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006284 /* print the error */
6285 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6286 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006287 }
6288 }
6289
Radek Krejci010e54b2016-03-15 09:40:34 +01006290 ly_vlog_hide(0);
6291
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006292 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006293 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6294 * all the validation errors
6295 */
6296 for (i = 0; i < unres->count; ++i) {
6297 if (unres->type[i] == UNRES_RESOLVED) {
6298 continue;
6299 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006300 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006301 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006302 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006303 }
6304
Michal Vaskoe8734262016-09-29 14:12:06 +02006305 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006306 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006307 return EXIT_SUCCESS;
6308}
6309
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006310/**
Michal Vaskobb211122015-08-19 14:03:11 +02006311 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006312 *
6313 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006314 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006315 * @param[in] item Item to resolve. Type determined by \p type.
6316 * @param[in] type Type of the unresolved item.
6317 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006318 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006319 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006320 */
6321int
Radek Krejci48464ed2016-03-17 15:44:09 +01006322unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6323 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006324{
Radek Krejci54081ce2016-08-12 15:21:47 +02006325 int rc;
6326 const char *dictstr;
6327
6328 dictstr = lydict_insert(mod->ctx, str, 0);
6329 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6330
6331 if (rc == -1) {
6332 lydict_remove(mod->ctx, dictstr);
6333 }
6334 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006335}
6336
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006337/**
Michal Vaskobb211122015-08-19 14:03:11 +02006338 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006339 *
6340 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006341 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006342 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006343 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006344 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006345 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006346 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006347 */
6348int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006349unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006350 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006351{
Michal Vaskoef486d72016-09-27 12:10:44 +02006352 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006353 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006354 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006355
Michal Vasko9bf425b2015-10-22 11:42:03 +02006356 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6357 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006358
Michal Vaskoef486d72016-09-27 12:10:44 +02006359 if (*ly_vlog_hide_location()) {
6360 log_hidden = 1;
6361 } else {
6362 log_hidden = 0;
6363 ly_vlog_hide(1);
6364 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006365 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006366 if (!log_hidden) {
6367 ly_vlog_hide(0);
6368 }
6369
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006370 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006371 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006372 if (ly_log_level >= LY_LLERR) {
6373 path = strdup(ly_errpath());
6374 msg = strdup(ly_errmsg());
6375 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6376 free(path);
6377 free(msg);
6378 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006379 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006380 if (type == UNRES_LIST_UNIQ) {
6381 /* free the allocated structure */
6382 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006383 } else if (rc == -1 && type == UNRES_IFFEAT) {
6384 /* free the allocated resources */
6385 free(*((char **)item));
6386 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006387 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006388 } else {
6389 /* erase info about validation errors */
6390 ly_errno = LY_SUCCESS;
6391 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006392 }
6393
Radek Krejci48464ed2016-03-17 15:44:09 +01006394 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006395
Michal Vasko88c29542015-11-27 14:57:53 +01006396 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006397 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006398 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006399 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6400 lyxml_unlink_elem(mod->ctx, yin, 1);
6401 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6402 }
Michal Vasko88c29542015-11-27 14:57:53 +01006403 }
6404
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006405 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006406 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6407 if (!unres->item) {
6408 LOGMEM;
6409 return -1;
6410 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006411 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006412 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6413 if (!unres->type) {
6414 LOGMEM;
6415 return -1;
6416 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006417 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006418 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6419 if (!unres->str_snode) {
6420 LOGMEM;
6421 return -1;
6422 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006423 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006424 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6425 if (!unres->module) {
6426 LOGMEM;
6427 return -1;
6428 }
6429 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006430
Michal Vasko3767fb22016-07-21 12:10:57 +02006431 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006432}
6433
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006434/**
Michal Vaskobb211122015-08-19 14:03:11 +02006435 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006436 *
6437 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006438 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006439 * @param[in] item Old item to be resolved.
6440 * @param[in] type Type of the old unresolved item.
6441 * @param[in] new_item New item to use in the duplicate.
6442 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006443 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006444 */
Michal Vaskodad19402015-08-06 09:51:53 +02006445int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006446unres_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 +02006447{
6448 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006449 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006450 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006451
Michal Vaskocf024702015-10-08 15:01:42 +02006452 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006453
Radek Krejcid09d1a52016-08-11 14:05:45 +02006454 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6455 if (type == UNRES_LIST_UNIQ) {
6456 aux_uniq.list = item;
6457 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6458 item = &aux_uniq;
6459 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006460 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006461
6462 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006463 if (type == UNRES_LIST_UNIQ) {
6464 free(new_item);
6465 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006466 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006467 }
6468
Radek Krejcic79c6b12016-07-26 15:11:49 +02006469 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006470 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006471 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006472 LOGINT;
6473 return -1;
6474 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006475 } else if (type == UNRES_IFFEAT) {
6476 /* duplicate unres_iffeature_data */
6477 iff_data = malloc(sizeof *iff_data);
6478 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6479 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6480 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6481 LOGINT;
6482 return -1;
6483 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006484 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006485 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006486 LOGINT;
6487 return -1;
6488 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006489 }
Michal Vaskodad19402015-08-06 09:51:53 +02006490
6491 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006492}
6493
Michal Vaskof02e3742015-08-05 16:27:02 +02006494/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006495int
Michal Vasko878e38d2016-09-05 12:17:53 +02006496unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006497{
Michal Vasko878e38d2016-09-05 12:17:53 +02006498 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006499 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006500
Michal Vasko878e38d2016-09-05 12:17:53 +02006501 if (start_on_backwards > 0) {
6502 i = start_on_backwards;
6503 } else {
6504 i = unres->count - 1;
6505 }
6506 for (; i > -1; i--) {
6507 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006508 continue;
6509 }
6510 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006511 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006512 break;
6513 }
6514 } else {
6515 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6516 aux_uniq2 = (struct unres_list_uniq *)item;
6517 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006518 break;
6519 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006520 }
6521 }
6522
Michal Vasko878e38d2016-09-05 12:17:53 +02006523 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006524}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006525
Michal Vaskoede9c472016-06-07 09:38:15 +02006526static void
6527unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6528{
6529 struct lyxml_elem *yin;
6530 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006531 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006532
6533 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006534 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006535 case UNRES_TYPE_DER:
6536 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6537 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6538 yang =(struct yang_type *)yin;
6539 yang->type->base = yang->base;
6540 lydict_remove(ctx, yang->name);
6541 free(yang);
6542 } else {
6543 lyxml_free(ctx, yin);
6544 }
6545 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006546 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006547 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6548 lydict_remove(ctx, iff_data->fname);
6549 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006550 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006551 case UNRES_IDENT:
6552 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006553 case UNRES_TYPE_DFLT:
6554 case UNRES_CHOICE_DFLT:
6555 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006556 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6557 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006558 case UNRES_LIST_UNIQ:
6559 free(unres->item[i]);
6560 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006561 default:
6562 break;
6563 }
6564 unres->type[i] = UNRES_RESOLVED;
6565}
6566
Michal Vasko88c29542015-11-27 14:57:53 +01006567void
Radek Krejcic071c542016-01-27 14:57:51 +01006568unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006569{
6570 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006571 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006572
Radek Krejcic071c542016-01-27 14:57:51 +01006573 if (!unres || !(*unres)) {
6574 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006575 }
6576
Radek Krejcic071c542016-01-27 14:57:51 +01006577 assert(module || (*unres)->count == 0);
6578
6579 for (i = 0; i < (*unres)->count; ++i) {
6580 if ((*unres)->module[i] != module) {
6581 if ((*unres)->type[i] != UNRES_RESOLVED) {
6582 unresolved++;
6583 }
6584 continue;
6585 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006586
6587 /* free heap memory for the specific item */
6588 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006589 }
6590
Michal Vaskoede9c472016-06-07 09:38:15 +02006591 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006592 if (!module || (!unresolved && !module->type)) {
6593 free((*unres)->item);
6594 free((*unres)->type);
6595 free((*unres)->str_snode);
6596 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006597 free((*unres));
6598 (*unres) = NULL;
6599 }
Michal Vasko88c29542015-11-27 14:57:53 +01006600}
6601
Radek Krejci7de36cf2016-09-12 16:18:50 +02006602static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006603resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006604{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006605 struct unres_data matches;
6606 uint32_t i;
6607
Radek Krejci9b6aad22016-09-20 15:55:51 +02006608 assert(type->base == LY_TYPE_LEAFREF);
6609
6610 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006611 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006612
6613 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006614 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006615 return -1;
6616 }
6617
6618 /* check that value matches */
6619 for (i = 0; i < matches.count; ++i) {
6620 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6621 leaf->value.leafref = matches.node[i];
6622 break;
6623 }
6624 }
6625
6626 free(matches.node);
6627
6628 if (!leaf->value.leafref) {
6629 /* reference not found */
6630 if (type->info.lref.req > -1) {
6631 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6632 return EXIT_FAILURE;
6633 } else {
6634 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6635 }
6636 }
6637
6638 return EXIT_SUCCESS;
6639}
6640
Radek Krejci9b6aad22016-09-20 15:55:51 +02006641API LY_DATA_TYPE
6642lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6643{
6644 struct lyd_node *node;
6645 struct lys_type *type, *type_iter;
6646 lyd_val value;
6647 int f = 0, r;
6648
6649 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6650 return LY_TYPE_ERR;
6651 }
6652
6653 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6654 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6655 /* we can get the type directly from the data node (it was already resolved) */
6656 return leaf->value_type & LY_DATA_TYPE_MASK;
6657 }
6658
6659 /* init */
6660 type = &((struct lys_node_leaf *)leaf->schema)->type;
6661 value = leaf->value;
6662 ly_vlog_hide(1);
6663
6664 /* resolve until we get the real data type */
6665 while (1) {
6666 /* get the correct data type from schema */
6667 switch (type->base) {
6668 case LY_TYPE_LEAFREF:
6669 type = &type->info.lref.target->type;
6670 break; /* continue in while loop */
6671 case LY_TYPE_UNION:
6672 type_iter = NULL;
6673 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6674 if (type_iter->base == LY_TYPE_LEAFREF) {
6675 if (type_iter->info.lref.req == -1) {
6676 /* target not required, so it always succeeds */
6677 break;
6678 } else {
6679 /* try to resolve leafref */
6680 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6681 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6682 /* revert leaf's content affected by resolve_leafref */
6683 ((struct lyd_node_leaf_list *)leaf)->value = value;
6684 if (!r) {
6685 /* success, we can continue with the leafref type */
6686 break;
6687 }
6688 }
6689 } else if (type_iter->base == LY_TYPE_INST) {
6690 if (type_iter->info.inst.req == -1) {
6691 /* target not required, so it always succeeds */
6692 return LY_TYPE_INST;
6693 } else {
6694 /* try to resolve instance-identifier */
6695 ly_errno = 0;
6696 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6697 if (!ly_errno && node) {
6698 /* the real type is instance-identifier */
6699 return LY_TYPE_INST;
6700 }
6701 }
6702 } else {
Radek Krejcif9837a82016-10-27 10:14:05 +02006703 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, NULL, 1);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006704 /* revert leaf's content affected by resolve_leafref */
6705 ((struct lyd_node_leaf_list *)leaf)->value = value;
6706 if (!r) {
6707 /* we have the real type */
6708 return type_iter->base;
6709 }
6710 }
6711 f = 0;
6712 }
6713 /* erase ly_errno and ly_vecode */
6714 ly_errno = LY_SUCCESS;
6715 ly_vecode = LYVE_SUCCESS;
6716
6717 if (!type_iter) {
6718 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6719 return LY_TYPE_ERR;
6720 }
6721 type = type_iter;
6722 break;
6723 default:
6724 /* we have the real type */
6725 ly_vlog_hide(0);
6726 return type->base;
6727 }
6728 }
6729
6730 ly_vlog_hide(0);
6731 return LY_TYPE_ERR;
6732}
6733
6734static int
6735resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6736{
6737 struct lys_type *datatype = NULL;
6738 int f = 0;
6739
6740 assert(type->base == LY_TYPE_UNION);
6741
6742 memset(&leaf->value, 0, sizeof leaf->value);
6743 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6744 leaf->value_type = datatype->base;
6745
6746 if (datatype->base == LY_TYPE_LEAFREF) {
6747 /* try to resolve leafref */
6748 if (!resolve_leafref(leaf, datatype)) {
6749 /* success */
6750 break;
6751 }
6752 } else if (datatype->base == LY_TYPE_INST) {
6753 /* try to resolve instance-identifier */
6754 ly_errno = 0;
6755 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6756 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6757 /* success */
6758 break;
6759 }
6760 } else {
Radek Krejcif9837a82016-10-27 10:14:05 +02006761 if (!lyp_parse_value_type(leaf, datatype, NULL, 1)) {
Radek Krejci9b6aad22016-09-20 15:55:51 +02006762 /* success */
6763 break;
6764 }
6765 }
6766 f = 0;
6767 }
6768 /* erase ly_errno and ly_vecode */
6769 ly_errno = LY_SUCCESS;
6770 ly_vecode = LYVE_SUCCESS;
6771
6772 if (!datatype) {
6773 /* failure */
6774 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6775 return EXIT_FAILURE;
6776 }
6777
6778 return EXIT_SUCCESS;
6779}
6780
Michal Vasko8bcdf292015-08-19 14:04:43 +02006781/**
6782 * @brief Resolve a single unres data item. Logs directly.
6783 *
Michal Vaskocf024702015-10-08 15:01:42 +02006784 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006785 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006786 *
6787 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6788 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006789int
Radek Krejci48464ed2016-03-17 15:44:09 +01006790resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006791{
Michal Vasko0491ab32015-08-19 14:28:29 +02006792 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006793 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006794 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006795
Michal Vasko83a6c462015-10-08 16:43:53 +02006796 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006797 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006798
Michal Vaskocf024702015-10-08 15:01:42 +02006799 switch (type) {
6800 case UNRES_LEAFREF:
6801 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006802 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006803
Michal Vaskocf024702015-10-08 15:01:42 +02006804 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006805 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006806 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006807 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006808 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006809 if (ly_errno) {
6810 return -1;
6811 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006812 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006813 return EXIT_FAILURE;
6814 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006815 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006816 }
6817 }
Michal Vaskocf024702015-10-08 15:01:42 +02006818 break;
6819
Radek Krejci7de36cf2016-09-12 16:18:50 +02006820 case UNRES_UNION:
6821 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006822 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006823
Michal Vaskocf024702015-10-08 15:01:42 +02006824 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006825 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006826 return rc;
6827 }
6828 break;
6829
Michal Vaskobf19d252015-10-08 15:39:17 +02006830 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006831 if ((rc = resolve_must(node, 0))) {
6832 return rc;
6833 }
6834 break;
6835
6836 case UNRES_MUST_INOUT:
6837 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006838 return rc;
6839 }
6840 break;
6841
Michal Vaskocf024702015-10-08 15:01:42 +02006842 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006843 LOGINT;
6844 return -1;
6845 }
6846
6847 return EXIT_SUCCESS;
6848}
6849
6850/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006851 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006852 *
6853 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006854 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006855 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006856 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006857 */
6858int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006859unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006860{
Radek Krejci03b71f72016-03-16 11:10:09 +01006861 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006862 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02006863 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006864
Radek Krejci03b71f72016-03-16 11:10:09 +01006865 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006866 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6867 if (!unres->node) {
6868 LOGMEM;
6869 return -1;
6870 }
Michal Vaskocf024702015-10-08 15:01:42 +02006871 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006872 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6873 if (!unres->type) {
6874 LOGMEM;
6875 return -1;
6876 }
Michal Vaskocf024702015-10-08 15:01:42 +02006877 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006878
Radek Krejci0b7704f2016-03-18 12:16:14 +01006879 if (type == UNRES_WHEN) {
6880 /* remove previous result */
6881 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006882 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006883
6884 return EXIT_SUCCESS;
6885}
6886
6887/**
6888 * @brief Resolve every unres data item in the structure. Logs directly.
6889 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006890 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6891 * unresolved leafrefs/instids are accepted).
6892 *
6893 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6894 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006895 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006896 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6897 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006898 *
6899 * @return EXIT_SUCCESS on success, -1 on error.
6900 */
6901int
Radek Krejci082c84f2016-10-17 16:33:06 +02006902resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006903{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006904 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006905 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006906 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006907 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006908 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006909
Radek Krejci082c84f2016-10-17 16:33:06 +02006910 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006911 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006912
6913 if (!unres->count) {
6914 return EXIT_SUCCESS;
6915 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006916
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006917 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006918 ly_vlog_hide(1);
6919
Radek Krejci0b7704f2016-03-18 12:16:14 +01006920 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006921 ly_errno = LY_SUCCESS;
6922 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006923 do {
6924 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006925 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006926 if (unres->type[i] != UNRES_WHEN) {
6927 continue;
6928 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006929 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006930 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006931 /* count when-stmt nodes in unres list */
6932 when_stmt++;
6933 }
6934
6935 /* resolve when condition only when all parent when conditions are already resolved */
6936 for (parent = unres->node[i]->parent;
6937 parent && LYD_WHEN_DONE(parent->when_status);
6938 parent = parent->parent) {
6939 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6940 /* the parent node was already unlinked, do not resolve this node,
6941 * it will be removed anyway, so just mark it as resolved
6942 */
6943 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6944 unres->type[i] = UNRES_RESOLVED;
6945 resolved++;
6946 break;
6947 }
6948 }
6949 if (parent) {
6950 continue;
6951 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006952
Radek Krejci48464ed2016-03-17 15:44:09 +01006953 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006954 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006955 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006956 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006957 /* false when condition */
6958 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006959 if (ly_log_level >= LY_LLERR) {
6960 path = strdup(ly_errpath());
6961 msg = strdup(ly_errmsg());
6962 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6963 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6964 free(path);
6965 free(msg);
6966 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006967 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006968 } /* follows else */
6969
Radek Krejci0c0086a2016-03-24 15:20:28 +01006970 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6971 /* if it has parent non-presence containers that would be empty, we should actually
6972 * remove the container
6973 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006974 for (parent = unres->node[i];
6975 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6976 parent = parent->parent) {
6977 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6978 /* presence container */
6979 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006980 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006981 if (parent->next || parent->prev != parent) {
6982 /* non empty (the child we are in and we are going to remove is not the only child) */
6983 break;
6984 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006985 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006986 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006987
Radek Krejci0b7704f2016-03-18 12:16:14 +01006988 /* auto-delete */
6989 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6990 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006991 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006992 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006993 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006994
Radek Krejci0b7704f2016-03-18 12:16:14 +01006995 lyd_unlink(unres->node[i]);
6996 unres->type[i] = UNRES_DELETE;
6997 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006998
6999 /* update the rest of unres items */
7000 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007001 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007002 continue;
7003 }
7004
7005 /* test if the node is in subtree to be deleted */
7006 for (parent = unres->node[j]; parent; parent = parent->parent) {
7007 if (parent == unres->node[i]) {
7008 /* yes, it is */
7009 unres->type[j] = UNRES_RESOLVED;
7010 resolved++;
7011 break;
7012 }
7013 }
7014 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007015 } else {
7016 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007017 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007018 ly_errno = LY_SUCCESS;
7019 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007020 resolved++;
7021 progress = 1;
7022 } else if (rc == -1) {
7023 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007024 /* print only this last error */
7025 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007026 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007027 } else {
7028 /* forward reference, erase ly_errno */
7029 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007030 }
7031 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007032 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007033 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007034
Radek Krejci0b7704f2016-03-18 12:16:14 +01007035 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007036 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007037 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02007038 if (ly_log_level >= LY_LLERR) {
7039 path = strdup(ly_errpath());
7040 msg = strdup(ly_errmsg());
7041 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
7042 free(path);
7043 free(msg);
7044 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007045 return -1;
7046 }
7047
7048 for (i = 0; del_items && i < unres->count; i++) {
7049 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7050 if (unres->type[i] != UNRES_DELETE) {
7051 continue;
7052 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007053 if (!unres->node[i]) {
7054 unres->type[i] = UNRES_RESOLVED;
7055 del_items--;
7056 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007057 }
7058
7059 /* really remove the complete subtree */
7060 lyd_free(unres->node[i]);
7061 unres->type[i] = UNRES_RESOLVED;
7062 del_items--;
7063 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007064
7065 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007066 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007067 if (unres->type[i] == UNRES_RESOLVED) {
7068 continue;
7069 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007070 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007071
Radek Krejci48464ed2016-03-17 15:44:09 +01007072 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007073 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007074 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007075 /* print only this last error */
7076 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007077 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007078 } 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 +02007079 unres->type[i] = UNRES_RESOLVED;
7080 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007081 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007082 /* accept it in this case */
7083 if (unres->type[i] == UNRES_LEAFREF) {
7084 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7085 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7086 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7087 } else {
7088 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7089 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7090 }
7091 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007092 }
7093 }
7094
Radek Krejci010e54b2016-03-15 09:40:34 +01007095 ly_vlog_hide(0);
7096 if (resolved < unres->count) {
7097 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7098 * all the validation errors
7099 */
7100 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007101 if (unres->type[i] == UNRES_UNION) {
7102 /* does not make sense to print specific errors for all
7103 * the data types, just print that the value is invalid */
7104 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7105 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7106 leaf->schema->name);
7107 } else if (unres->type[i] != UNRES_RESOLVED) {
7108 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007109 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007110 }
7111 return -1;
7112 }
7113
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007114 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007115 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007116 return EXIT_SUCCESS;
7117}