blob: 227bc1b3c3ae364040e130cc45570c0e4df2a0fa [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 Vasko730dfdf2015-08-11 14:48:05 +020033/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020034 * @brief Parse an identifier.
35 *
36 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
37 * identifier = (ALPHA / "_")
38 * *(ALPHA / DIGIT / "_" / "-" / ".")
39 *
Michal Vaskobb211122015-08-19 14:03:11 +020040 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020041 *
42 * @return Number of characters successfully parsed.
43 */
Michal Vasko249e6b52015-08-19 11:08:52 +020044int
Radek Krejci6dc53a22015-08-17 13:27:59 +020045parse_identifier(const char *id)
46{
47 int parsed = 0;
48
Michal Vasko1ab90bc2016-03-15 10:40:22 +010049 assert(id);
50
Radek Krejci6dc53a22015-08-17 13:27:59 +020051 if (((id[0] == 'x') || (id[0] == 'X'))
Michal Vasko1ab90bc2016-03-15 10:40:22 +010052 && (id[0] && ((id[1] == 'm') || (id[0] == 'M')))
53 && (id[1] && ((id[2] == 'l') || (id[2] == 'L')))) {
Radek Krejci6dc53a22015-08-17 13:27:59 +020054 return -parsed;
55 }
56
57 if (!isalpha(id[0]) && (id[0] != '_')) {
58 return -parsed;
59 }
60
61 ++parsed;
62 ++id;
63
64 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
65 ++parsed;
66 ++id;
67 }
68
69 return parsed;
70}
71
72/**
73 * @brief Parse a node-identifier.
74 *
Michal Vasko723e50c2015-10-20 15:20:29 +020075 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020076 *
Michal Vaskobb211122015-08-19 14:03:11 +020077 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020078 * @param[out] mod_name Points to the module name, NULL if there is not any.
79 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020080 * @param[out] name Points to the node name.
81 * @param[out] nam_len Length of the node name.
82 *
83 * @return Number of characters successfully parsed,
84 * positive on success, negative on failure.
85 */
86static int
Michal Vasko723e50c2015-10-20 15:20:29 +020087parse_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 +020088{
89 int parsed = 0, ret;
90
91 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020092 if (mod_name) {
93 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020094 }
Michal Vasko723e50c2015-10-20 15:20:29 +020095 if (mod_name_len) {
96 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020097 }
98 if (name) {
99 *name = NULL;
100 }
101 if (nam_len) {
102 *nam_len = 0;
103 }
104
105 if ((ret = parse_identifier(id)) < 1) {
106 return ret;
107 }
108
Michal Vasko723e50c2015-10-20 15:20:29 +0200109 if (mod_name) {
110 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200111 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200112 if (mod_name_len) {
113 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114 }
115
116 parsed += ret;
117 id += ret;
118
119 /* there is prefix */
120 if (id[0] == ':') {
121 ++parsed;
122 ++id;
123
124 /* there isn't */
125 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200126 if (name && mod_name) {
127 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200128 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200129 if (mod_name) {
130 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200131 }
132
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (nam_len && mod_name_len) {
134 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 if (mod_name_len) {
137 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200138 }
139
140 return parsed;
141 }
142
143 /* identifier (node name) */
144 if ((ret = parse_identifier(id)) < 1) {
145 return -parsed+ret;
146 }
147
148 if (name) {
149 *name = id;
150 }
151 if (nam_len) {
152 *nam_len = ret;
153 }
154
155 return parsed+ret;
156}
157
158/**
159 * @brief Parse a path-predicate (leafref).
160 *
161 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
162 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
163 *
Michal Vaskobb211122015-08-19 14:03:11 +0200164 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200165 * @param[out] prefix Points to the prefix, NULL if there is not any.
166 * @param[out] pref_len Length of the prefix, 0 if there is not any.
167 * @param[out] name Points to the node name.
168 * @param[out] nam_len Length of the node name.
169 * @param[out] path_key_expr Points to the path-key-expr.
170 * @param[out] pke_len Length of the path-key-expr.
171 * @param[out] has_predicate Flag to mark whether there is another predicate following.
172 *
173 * @return Number of characters successfully parsed,
174 * positive on success, negative on failure.
175 */
176static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200177parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
178 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200179{
180 const char *ptr;
181 int parsed = 0, ret;
182
183 assert(id);
184 if (prefix) {
185 *prefix = NULL;
186 }
187 if (pref_len) {
188 *pref_len = 0;
189 }
190 if (name) {
191 *name = NULL;
192 }
193 if (nam_len) {
194 *nam_len = 0;
195 }
196 if (path_key_expr) {
197 *path_key_expr = NULL;
198 }
199 if (pke_len) {
200 *pke_len = 0;
201 }
202 if (has_predicate) {
203 *has_predicate = 0;
204 }
205
206 if (id[0] != '[') {
207 return -parsed;
208 }
209
210 ++parsed;
211 ++id;
212
213 while (isspace(id[0])) {
214 ++parsed;
215 ++id;
216 }
217
218 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
219 return -parsed+ret;
220 }
221
222 parsed += ret;
223 id += ret;
224
225 while (isspace(id[0])) {
226 ++parsed;
227 ++id;
228 }
229
230 if (id[0] != '=') {
231 return -parsed;
232 }
233
234 ++parsed;
235 ++id;
236
237 while (isspace(id[0])) {
238 ++parsed;
239 ++id;
240 }
241
242 if ((ptr = strchr(id, ']')) == NULL) {
243 return -parsed;
244 }
245
246 --ptr;
247 while (isspace(ptr[0])) {
248 --ptr;
249 }
250 ++ptr;
251
252 ret = ptr-id;
253 if (path_key_expr) {
254 *path_key_expr = id;
255 }
256 if (pke_len) {
257 *pke_len = ret;
258 }
259
260 parsed += ret;
261 id += ret;
262
263 while (isspace(id[0])) {
264 ++parsed;
265 ++id;
266 }
267
268 assert(id[0] == ']');
269
270 if (id[1] == '[') {
271 *has_predicate = 1;
272 }
273
274 return parsed+1;
275}
276
277/**
278 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
279 * the ".." and the first node-identifier, other calls parse a single
280 * node-identifier each.
281 *
282 * path-key-expr = current-function-invocation *WSP "/" *WSP
283 * rel-path-keyexpr
284 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
285 * *(node-identifier *WSP "/" *WSP)
286 * node-identifier
287 *
Michal Vaskobb211122015-08-19 14:03:11 +0200288 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200289 * @param[out] prefix Points to the prefix, NULL if there is not any.
290 * @param[out] pref_len Length of the prefix, 0 if there is not any.
291 * @param[out] name Points to the node name.
292 * @param[out] nam_len Length of the node name.
293 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
294 * must not be changed between consecutive calls.
295 * @return Number of characters successfully parsed,
296 * positive on success, negative on failure.
297 */
298static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200299parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
300 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200301{
302 int parsed = 0, ret, par_times = 0;
303
304 assert(id);
305 assert(parent_times);
306 if (prefix) {
307 *prefix = NULL;
308 }
309 if (pref_len) {
310 *pref_len = 0;
311 }
312 if (name) {
313 *name = NULL;
314 }
315 if (nam_len) {
316 *nam_len = 0;
317 }
318
319 if (!*parent_times) {
320 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
321 if (strncmp(id, "current()", 9)) {
322 return -parsed;
323 }
324
325 parsed += 9;
326 id += 9;
327
328 while (isspace(id[0])) {
329 ++parsed;
330 ++id;
331 }
332
333 if (id[0] != '/') {
334 return -parsed;
335 }
336
337 ++parsed;
338 ++id;
339
340 while (isspace(id[0])) {
341 ++parsed;
342 ++id;
343 }
344
345 /* rel-path-keyexpr */
346 if (strncmp(id, "..", 2)) {
347 return -parsed;
348 }
349 ++par_times;
350
351 parsed += 2;
352 id += 2;
353
354 while (isspace(id[0])) {
355 ++parsed;
356 ++id;
357 }
358 }
359
360 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
361 *
362 * first parent reference with whitespaces already parsed
363 */
364 if (id[0] != '/') {
365 return -parsed;
366 }
367
368 ++parsed;
369 ++id;
370
371 while (isspace(id[0])) {
372 ++parsed;
373 ++id;
374 }
375
376 while (!strncmp(id, "..", 2) && !*parent_times) {
377 ++par_times;
378
379 parsed += 2;
380 id += 2;
381
382 while (isspace(id[0])) {
383 ++parsed;
384 ++id;
385 }
386
387 if (id[0] != '/') {
388 return -parsed;
389 }
390
391 ++parsed;
392 ++id;
393
394 while (isspace(id[0])) {
395 ++parsed;
396 ++id;
397 }
398 }
399
400 if (!*parent_times) {
401 *parent_times = par_times;
402 }
403
404 /* all parent references must be parsed at this point */
405 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
406 return -parsed+ret;
407 }
408
409 parsed += ret;
410 id += ret;
411
412 return parsed;
413}
414
415/**
416 * @brief Parse path-arg (leafref).
417 *
418 * path-arg = absolute-path / relative-path
419 * absolute-path = 1*("/" (node-identifier *path-predicate))
420 * relative-path = 1*(".." "/") descendant-path
421 *
Michal Vaskobb211122015-08-19 14:03:11 +0200422 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200423 * @param[out] prefix Points to the prefix, NULL if there is not any.
424 * @param[out] pref_len Length of the prefix, 0 if there is not any.
425 * @param[out] name Points to the node name.
426 * @param[out] nam_len Length of the node name.
427 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
428 * must not be changed between consecutive calls. -1 if the
429 * path is relative.
430 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
431 *
432 * @return Number of characters successfully parsed,
433 * positive on success, negative on failure.
434 */
435static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200436parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
437 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200438{
439 int parsed = 0, ret, par_times = 0;
440
441 assert(id);
442 assert(parent_times);
443 if (prefix) {
444 *prefix = NULL;
445 }
446 if (pref_len) {
447 *pref_len = 0;
448 }
449 if (name) {
450 *name = NULL;
451 }
452 if (nam_len) {
453 *nam_len = 0;
454 }
455 if (has_predicate) {
456 *has_predicate = 0;
457 }
458
459 if (!*parent_times && !strncmp(id, "..", 2)) {
460 ++par_times;
461
462 parsed += 2;
463 id += 2;
464
465 while (!strncmp(id, "/..", 3)) {
466 ++par_times;
467
468 parsed += 3;
469 id += 3;
470 }
471 }
472
473 if (!*parent_times) {
474 if (par_times) {
475 *parent_times = par_times;
476 } else {
477 *parent_times = -1;
478 }
479 }
480
481 if (id[0] != '/') {
482 return -parsed;
483 }
484
485 /* skip '/' */
486 ++parsed;
487 ++id;
488
489 /* node-identifier ([prefix:]identifier) */
490 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
491 return -parsed-ret;
492 }
493
494 parsed += ret;
495 id += ret;
496
497 /* there is no predicate */
498 if ((id[0] == '/') || !id[0]) {
499 return parsed;
500 } else if (id[0] != '[') {
501 return -parsed;
502 }
503
504 if (has_predicate) {
505 *has_predicate = 1;
506 }
507
508 return parsed;
509}
510
511/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200512 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200513 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200514 *
515 * instance-identifier = 1*("/" (node-identifier *predicate))
516 *
Michal Vaskobb211122015-08-19 14:03:11 +0200517 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200518 * @param[out] model Points to the model name.
519 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200520 * @param[out] name Points to the node name.
521 * @param[out] nam_len Length of the node name.
522 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
523 *
524 * @return Number of characters successfully parsed,
525 * positive on success, negative on failure.
526 */
527static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200528parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
529 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200530{
531 int parsed = 0, ret;
532
533 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200534 if (model) {
535 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200536 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200537 if (mod_len) {
538 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200539 }
540 if (name) {
541 *name = NULL;
542 }
543 if (nam_len) {
544 *nam_len = 0;
545 }
546 if (has_predicate) {
547 *has_predicate = 0;
548 }
549
550 if (id[0] != '/') {
551 return -parsed;
552 }
553
554 ++parsed;
555 ++id;
556
Michal Vasko1f2cc332015-08-19 11:18:32 +0200557 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Michal Vaskobea08e92016-05-18 13:28:08 +0200558 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200559 }
560
561 parsed += ret;
562 id += ret;
563
564 if ((id[0] == '[') && has_predicate) {
565 *has_predicate = 1;
566 }
567
568 return parsed;
569}
570
571/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200572 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200573 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574 *
575 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
576 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
577 * ((DQUOTE string DQUOTE) /
578 * (SQUOTE string SQUOTE))
579 * pos = non-negative-integer-value
580 *
Michal Vaskobb211122015-08-19 14:03:11 +0200581 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200582 * @param[out] model Points to the model name.
583 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200584 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
585 * @param[out] nam_len Length of the node name.
586 * @param[out] value Value the node-identifier must have (string from the grammar),
587 * NULL if there is not any.
588 * @param[out] val_len Length of the value, 0 if there is not any.
589 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
590 *
591 * @return Number of characters successfully parsed,
592 * positive on success, negative on failure.
593 */
594static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200595parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
596 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597{
598 const char *ptr;
599 int parsed = 0, ret;
600 char quote;
601
602 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200603 if (model) {
604 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200605 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200606 if (mod_len) {
607 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200608 }
609 if (name) {
610 *name = NULL;
611 }
612 if (nam_len) {
613 *nam_len = 0;
614 }
615 if (value) {
616 *value = NULL;
617 }
618 if (val_len) {
619 *val_len = 0;
620 }
621 if (has_predicate) {
622 *has_predicate = 0;
623 }
624
625 if (id[0] != '[') {
626 return -parsed;
627 }
628
629 ++parsed;
630 ++id;
631
632 while (isspace(id[0])) {
633 ++parsed;
634 ++id;
635 }
636
637 /* pos */
638 if (isdigit(id[0])) {
639 if (name) {
640 *name = id;
641 }
642
643 if (id[0] == '0') {
644 ++parsed;
645 ++id;
646
647 if (isdigit(id[0])) {
648 return -parsed;
649 }
650 }
651
652 while (isdigit(id[0])) {
653 ++parsed;
654 ++id;
655 }
656
657 if (nam_len) {
658 *nam_len = id-(*name);
659 }
660
661 /* "." */
662 } else if (id[0] == '.') {
663 if (name) {
664 *name = id;
665 }
666 if (nam_len) {
667 *nam_len = 1;
668 }
669
670 ++parsed;
671 ++id;
672
673 /* node-identifier */
674 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200675 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200677 } else if (model && !*model) {
678 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200679 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680
681 parsed += ret;
682 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 }
684
685 while (isspace(id[0])) {
686 ++parsed;
687 ++id;
688 }
689
690 if (id[0] != '=') {
691 return -parsed;
692 }
693
694 ++parsed;
695 ++id;
696
697 while (isspace(id[0])) {
698 ++parsed;
699 ++id;
700 }
701
702 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
703 if ((id[0] == '\"') || (id[0] == '\'')) {
704 quote = id[0];
705
706 ++parsed;
707 ++id;
708
709 if ((ptr = strchr(id, quote)) == NULL) {
710 return -parsed;
711 }
712 ret = ptr-id;
713
714 if (value) {
715 *value = id;
716 }
717 if (val_len) {
718 *val_len = ret;
719 }
720
721 parsed += ret+1;
722 id += ret+1;
723 } else {
724 return -parsed;
725 }
726
727 while (isspace(id[0])) {
728 ++parsed;
729 ++id;
730 }
731
732 if (id[0] != ']') {
733 return -parsed;
734 }
735
736 ++parsed;
737 ++id;
738
739 if ((id[0] == '[') && has_predicate) {
740 *has_predicate = 1;
741 }
742
743 return parsed;
744}
745
746/**
747 * @brief Parse schema-nodeid.
748 *
749 * schema-nodeid = absolute-schema-nodeid /
750 * descendant-schema-nodeid
751 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200752 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200753 * node-identifier
754 * absolute-schema-nodeid
755 *
Michal Vaskobb211122015-08-19 14:03:11 +0200756 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200757 * @param[out] mod_name Points to the module name, NULL if there is not any.
758 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200759 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] nam_len Length of the node name.
761 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
762 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100763 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
764 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 *
766 * @return Number of characters successfully parsed,
767 * positive on success, negative on failure.
768 */
Michal Vasko22448d32016-03-16 13:17:29 +0100769int
Michal Vasko723e50c2015-10-20 15:20:29 +0200770parse_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 +0100771 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200772{
773 int parsed = 0, ret;
774
775 assert(id);
776 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200777 if (mod_name) {
778 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200779 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200780 if (mod_name_len) {
781 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
783 if (name) {
784 *name = NULL;
785 }
786 if (nam_len) {
787 *nam_len = 0;
788 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100789 if (has_predicate) {
790 *has_predicate = 0;
791 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200792
793 if (id[0] != '/') {
794 if (*is_relative != -1) {
795 return -parsed;
796 } else {
797 *is_relative = 1;
798 }
Michal Vasko48935352016-03-29 11:52:36 +0200799 if (!strncmp(id, "./", 2)) {
800 parsed += 2;
801 id += 2;
802 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200803 } else {
804 if (*is_relative == -1) {
805 *is_relative = 0;
806 }
807 ++parsed;
808 ++id;
809 }
810
Michal Vasko723e50c2015-10-20 15:20:29 +0200811 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200812 return -parsed+ret;
813 }
814
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100815 parsed += ret;
816 id += ret;
817
818 if ((id[0] == '[') && has_predicate) {
819 *has_predicate = 1;
820 }
821
822 return parsed;
823}
824
825/**
826 * @brief Parse schema predicate (special format internally used).
827 *
828 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200829 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100830 * key-with-value = identifier *WSP "=" *WSP
831 * ((DQUOTE string DQUOTE) /
832 * (SQUOTE string SQUOTE))
833 *
834 * @param[in] id Identifier to use.
835 * @param[out] name Points to the list key name.
836 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100837 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100838 * @param[out] val_len Length of \p value.
839 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
840 */
Michal Vasko22448d32016-03-16 13:17:29 +0100841int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200842parse_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 +0100843 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100844{
845 const char *ptr;
846 int parsed = 0, ret;
847 char quote;
848
849 assert(id);
850 if (name) {
851 *name = NULL;
852 }
853 if (nam_len) {
854 *nam_len = 0;
855 }
856 if (value) {
857 *value = NULL;
858 }
859 if (val_len) {
860 *val_len = 0;
861 }
862 if (has_predicate) {
863 *has_predicate = 0;
864 }
865
866 if (id[0] != '[') {
867 return -parsed;
868 }
869
870 ++parsed;
871 ++id;
872
873 while (isspace(id[0])) {
874 ++parsed;
875 ++id;
876 }
877
Michal Vasko22448d32016-03-16 13:17:29 +0100878 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200879 if (id[0] == '.') {
880 ret = 1;
881 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100882 return -parsed + ret;
883 }
884 if (name) {
885 *name = id;
886 }
887 if (nam_len) {
888 *nam_len = ret;
889 }
890
891 parsed += ret;
892 id += ret;
893
894 while (isspace(id[0])) {
895 ++parsed;
896 ++id;
897 }
898
899 /* there is value as well */
900 if (id[0] == '=') {
901 ++parsed;
902 ++id;
903
904 while (isspace(id[0])) {
905 ++parsed;
906 ++id;
907 }
908
909 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
910 if ((id[0] == '\"') || (id[0] == '\'')) {
911 quote = id[0];
912
913 ++parsed;
914 ++id;
915
916 if ((ptr = strchr(id, quote)) == NULL) {
917 return -parsed;
918 }
919 ret = ptr - id;
920
921 if (value) {
922 *value = id;
923 }
924 if (val_len) {
925 *val_len = ret;
926 }
927
928 parsed += ret + 1;
929 id += ret + 1;
930 } else {
931 return -parsed;
932 }
933
934 while (isspace(id[0])) {
935 ++parsed;
936 ++id;
937 }
Michal Vasko22448d32016-03-16 13:17:29 +0100938 } else if (value) {
939 /* if value was expected, it's mandatory */
940 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100941 }
942
943 if (id[0] != ']') {
944 return -parsed;
945 }
946
947 ++parsed;
948 ++id;
949
950 if ((id[0] == '[') && has_predicate) {
951 *has_predicate = 1;
952 }
953
954 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200955}
956
957/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200958 * @brief Resolve (find) a feature definition. Logs directly.
959 *
960 * @param[in] feat_name Feature name to resolve.
961 * @param[in] len Length of \p feat_name.
962 * @param[in] node Node with the if-feature expression.
963 *
964 * @return 0 on disabled, 1 on enabled, 2 on forward reference, -1 on error.
965 */
966static int
967resolve_iffeature_feature(const char *feat_name, uint16_t len, const struct lys_node *node)
968{
969 char *str;
970 const char *mod_name, *name;
971 int mod_name_len, nam_len, i, j;
972 const struct lys_module *module;
973
974 /* check prefix */
975 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
976 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
977 return -1;
978 }
979
980 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
981 if (!module) {
982 /* identity refers unknown data model */
983 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
984 return -1;
985 }
986
987 /* search in the identified module ... */
988 for (j = 0; j < module->features_size; j++) {
989 if (!strcmp(name, module->features[j].name)) {
990 /* check status */
991 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
992 module->features[j].module, module->features[j].name, node)) {
993 return -1;
994 }
995 return (module->features[j].flags & LYS_FENABLED ? 1 : 0);
996 }
997 }
998 /* ... and all its submodules */
999 for (i = 0; i < module->inc_size; i++) {
1000 if (!module->inc[i].submodule) {
1001 /* not yet resolved */
1002 continue;
1003 }
1004 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
1005 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
1006 /* check status */
1007 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1008 module->inc[i].submodule->features[j].flags,
1009 module->inc[i].submodule->features[j].module,
1010 module->inc[i].submodule->features[j].name, node)) {
1011 return -1;
1012 }
1013 return (module->inc[i].submodule->features[j].flags & LYS_FENABLED ? 1 : 0);
1014 }
1015 }
1016 }
1017
1018 /* not found */
1019 str = strndup(feat_name, len);
1020 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1021 free(str);
1022 return 2;
1023}
1024
1025static int
1026resolve_iffeature_factor(const char *factor, uint16_t len, const struct lys_node *node)
1027{
1028 uint16_t cur_len;
1029 int ret;
1030
1031 if (isspace(factor[0])) {
1032 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, factor[0], factor);
1033 return -1;
1034 }
1035
1036 if ((len > 4) && (factor[0] == 'n') && (factor[1] == 'o') && (factor[2] == 't') && isspace(factor[3])) {
1037 /* not-keyword sep if-feature-factor */
1038 cur_len = 4;
1039 while (isspace(factor[cur_len])) {
1040 ++cur_len;
1041 if (cur_len > len) {
1042 LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
1043 return -1;
1044 }
1045 }
1046
1047 ret = resolve_iffeature_factor(factor + cur_len, len - cur_len, node);
1048 if ((ret == -1) || (ret == 2)) {
1049 return ret;;
1050 }
1051 return !ret;
1052 } else if (factor[0] == '(') {
1053 /* "(" sep if-feature-expr sep ")" */
1054 if (factor[len] != ')') {
1055 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, factor[len], &factor[len]);
1056 return -1;
1057 }
1058 cur_len = 1;
1059 while (isspace(factor[cur_len])) {
1060 ++cur_len;
1061 }
1062
1063 --len;
1064 while (isspace(factor[len])) {
1065 --len;
1066 }
1067
1068 return resolve_iffeature_expr(factor + cur_len, len - cur_len, node);
1069 } else {
1070 /* identifier-ref-arg */
1071 return resolve_iffeature_feature(factor, len, node);
1072 }
1073}
1074
1075static int
1076resolve_iffeature_term(const char *term, uint16_t len, const struct lys_node *node)
1077{
1078 uint16_t cur_len, factor_len, and_len;
1079 int ret1, ret2;
1080
1081 if (isspace(term[0])) {
1082 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, term[0], term);
1083 return -1;
1084 }
1085
1086 cur_len = 0;
1087 factor_len = 0;
1088 and_len = 0;
1089 while (cur_len < len) {
1090 ++cur_len;
1091 if ((cur_len > 1) && isspace(term[cur_len - 2]) && !and_len && (term[cur_len - 1] == 'a')) {
1092 and_len = 1;
1093 } else if ((and_len == 1) && (term[cur_len - 1] == 'n')) {
1094 and_len = 2;
1095 } else if ((and_len == 2) && (term[cur_len - 1] == 'd')) {
1096 and_len = 3;
1097 } else if ((and_len == 3) && isspace(term[cur_len - 1])) {
1098 and_len = 4;
1099 break;
1100 } else if (!isspace(term[cur_len - 1])) {
1101 factor_len = cur_len;
1102 }
1103 }
1104
1105 if (and_len == 4) {
1106 /* if-feature-factor sep and-keyword sep if-feature-term */
1107 while (isspace(term[cur_len])) {
1108 ++cur_len;
1109 if (cur_len > len) {
1110 LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
1111 return -1;
1112 }
1113 }
1114 ret1 = resolve_iffeature_factor(term, factor_len, node);
1115 if ((ret1 == -1) || (ret1 == 2)) {
1116 return ret1;
1117 }
1118 ret2 = resolve_iffeature_term(term + cur_len, len - cur_len, node);
1119 if ((ret2 == -1) || (ret2 == 2)) {
1120 return ret2;
1121 }
1122 return ret1 && ret2;
1123
1124 } else {
1125 /* if-feature-factor */
1126 if (and_len) {
1127 factor_len = cur_len;
1128 }
1129 return resolve_iffeature_factor(term, factor_len, node);
1130 }
1131}
1132
1133int
1134resolve_iffeature_expr(const char *expr, uint16_t len, const struct lys_node *node)
1135{
1136 uint16_t cur_len, term_len, or_len;
1137 int ret1, ret2;
1138
1139 if (isspace(expr[0])) {
1140 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, expr[0], expr);
1141 return -1;
1142 }
1143
1144 cur_len = 0;
1145 term_len = 0;
1146 or_len = 0;
1147 while (cur_len < len) {
1148 ++cur_len;
1149 if ((cur_len > 1) && isspace(expr[cur_len - 2]) && !or_len && (expr[cur_len - 1] == 'o')) {
1150 or_len = 1;
1151 } else if ((or_len == 1) && (expr[cur_len - 1] == 'r')) {
1152 or_len = 2;
1153 } else if ((or_len == 2) && isspace(expr[cur_len - 1])) {
1154 or_len = 3;
1155 break;
1156 } else if (!isspace(expr[cur_len - 1])) {
1157 term_len = cur_len;
1158 }
1159 }
1160
1161 if (or_len == 3) {
1162 /* if-feature-term sep or-keyword sep if-feature-expr */
1163 while (isspace(expr[cur_len])) {
1164 ++cur_len;
1165 if (cur_len > len) {
1166 LOGVAL(LYE_EOF, LY_VLOG_NONE, NULL);
1167 return -1;
1168 }
1169 }
1170 ret1 = resolve_iffeature_term(expr, term_len, node);
1171 if ((ret1 == -1) || (ret1 == 2)) {
1172 return ret1;
1173 }
1174 ret2 = resolve_iffeature_expr(expr + cur_len, len - cur_len, node);
1175 if ((ret2 == -1) || (ret2 == 2)) {
1176 return ret2;
1177 }
1178 return ret1 || ret2;
1179
1180 } else {
1181 /* if-feature-term */
1182 if (or_len) {
1183 term_len = cur_len;
1184 }
1185 return resolve_iffeature_term(expr, term_len, node);
1186 }
1187}
1188
1189/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001190 * @brief Resolve (find) a data node based on a schema-nodeid.
1191 *
1192 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1193 * module).
1194 *
1195 */
1196struct lyd_node *
1197resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1198{
1199 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001200 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001201 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001202 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001203
1204 assert(nodeid && start);
1205
1206 if (nodeid[0] == '/') {
1207 return NULL;
1208 }
1209
1210 str = p = strdup(nodeid);
1211 if (!str) {
1212 LOGMEM;
1213 return NULL;
1214 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001215
Michal Vasko3edeaf72016-02-11 13:17:43 +01001216 while (p) {
1217 token = p;
1218 p = strchr(p, '/');
1219 if (p) {
1220 *p = '\0';
1221 p++;
1222 }
1223
Radek Krejci5da4eb62016-04-08 14:45:51 +02001224 if (p) {
1225 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001226 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001227 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001228 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001229 result = NULL;
1230 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001231 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001232
Radek Krejci5da4eb62016-04-08 14:45:51 +02001233 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1234 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001235 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001236 /* shorthand case */
1237 if (!shorthand) {
1238 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001239 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001240 continue;
1241 } else {
1242 shorthand = 0;
1243 if (schema->nodetype == LYS_LEAF) {
1244 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1245 result = NULL;
1246 break;
1247 }
1248 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001249 }
1250 } else {
1251 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001252 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1253 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001254 || !schema) {
1255 result = NULL;
1256 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001257 }
1258 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001259 LY_TREE_FOR(result ? result->child : start, iter) {
1260 if (iter->schema == schema) {
1261 /* move in data tree according to returned schema */
1262 result = iter;
1263 break;
1264 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001265 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001266 if (!iter) {
1267 /* instance not found */
1268 result = NULL;
1269 break;
1270 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001271 }
1272 free(str);
1273
1274 return result;
1275}
1276
Radek Krejcibdf92362016-04-08 14:43:34 +02001277/*
1278 * 0 - ok (done)
1279 * 1 - continue
1280 * 2 - break
1281 * -1 - error
1282 */
1283static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001284schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001285 const struct lys_module *module, const char *mod_name, int mod_name_len,
1286 const struct lys_node **start)
1287{
1288 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001289 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001290
1291 /* module check */
1292 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1293 if (!prefix_mod) {
1294 return -1;
1295 }
1296 if (prefix_mod != lys_node_module(sibling)) {
1297 return 1;
1298 }
1299
1300 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001301 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001302 if (*shorthand != -1) {
1303 *shorthand = *shorthand ? 0 : 1;
1304 }
1305 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001306 }
1307
1308 /* the result node? */
1309 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001310 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001311 return 1;
1312 }
1313 return 0;
1314 }
1315
Radek Krejcicc217a62016-04-08 16:58:11 +02001316 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001317 /* move down the tree, if possible */
1318 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1319 return -1;
1320 }
1321 *start = sibling->child;
1322 }
1323
1324 return 2;
1325}
1326
Michal Vasko3edeaf72016-02-11 13:17:43 +01001327/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1328int
1329resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1330 const struct lys_node **ret)
1331{
1332 const char *name, *mod_name, *id;
1333 const struct lys_node *sibling;
1334 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001335 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001336 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001337 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001338
1339 assert(nodeid && (start || module) && !(start && module) && ret);
1340
1341 id = nodeid;
1342
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001343 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 +01001344 return ((id - nodeid) - r) + 1;
1345 }
1346 id += r;
1347
1348 if ((is_relative && !start) || (!is_relative && !module)) {
1349 return -1;
1350 }
1351
1352 /* descendant-schema-nodeid */
1353 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001354 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001355
1356 /* absolute-schema-nodeid */
1357 } else {
1358 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001359 if (!start_mod) {
1360 return -1;
1361 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001362 start = start_mod->data;
1363 }
1364
1365 while (1) {
1366 sibling = NULL;
1367 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1368 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1369 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001370 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001371 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1372 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001373 *ret = sibling;
1374 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001375 } else if (r == 1) {
1376 continue;
1377 } else if (r == 2) {
1378 break;
1379 } else {
1380 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001381 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001382 }
1383 }
1384
1385 /* no match */
1386 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001387 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001388 return EXIT_SUCCESS;
1389 }
1390
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001391 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 +01001392 return ((id - nodeid) - r) + 1;
1393 }
1394 id += r;
1395 }
1396
1397 /* cannot get here */
1398 LOGINT;
1399 return -1;
1400}
1401
Radek Krejcif3c71de2016-04-11 12:45:46 +02001402/* unique, refine,
1403 * >0 - unexpected char on position (ret - 1),
1404 * 0 - ok (but ret can still be NULL),
1405 * -1 - error,
1406 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001407int
1408resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001409 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001410{
1411 const char *name, *mod_name, *id;
1412 const struct lys_node *sibling;
1413 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001414 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001415 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001416 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001417
1418 assert(nodeid && start && ret);
1419 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1420
1421 id = nodeid;
1422 module = start->module;
1423
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001424 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 +01001425 return ((id - nodeid) - r) + 1;
1426 }
1427 id += r;
1428
1429 if (!is_relative) {
1430 return -1;
1431 }
1432
1433 while (1) {
1434 sibling = NULL;
1435 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1436 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1437 /* name match */
1438 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001439 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1440 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001441 if (!(sibling->nodetype & ret_nodetype)) {
1442 /* wrong node type, too bad */
1443 continue;
1444 }
1445 *ret = sibling;
1446 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001447 } else if (r == 1) {
1448 continue;
1449 } else if (r == 2) {
1450 break;
1451 } else {
1452 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001453 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001454 }
1455 }
1456
1457 /* no match */
1458 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001459 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001460 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001461 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1462 *ret = NULL;
1463 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001464 }
1465
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001466 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 +01001467 return ((id - nodeid) - r) + 1;
1468 }
1469 id += r;
1470 }
1471
1472 /* cannot get here */
1473 LOGINT;
1474 return -1;
1475}
1476
1477/* choice default */
1478int
1479resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1480{
1481 /* cannot actually be a path */
1482 if (strchr(nodeid, '/')) {
1483 return -1;
1484 }
1485
Radek Krejcif3c71de2016-04-11 12:45:46 +02001486 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001487}
1488
1489/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1490static int
1491resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1492{
1493 const struct lys_module *module;
1494 const char *mod_prefix, *name;
1495 int i, mod_prefix_len, nam_len;
1496
1497 /* parse the identifier, it must be parsed on one call */
1498 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1499 return -i + 1;
1500 }
1501
1502 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1503 if (!module) {
1504 return -1;
1505 }
1506 if (module != start->module) {
1507 start = module->data;
1508 }
1509
1510 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1511
1512 return EXIT_SUCCESS;
1513}
1514
1515int
1516resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1517 const struct lys_node **ret)
1518{
1519 const char *name, *mod_name, *id;
1520 const struct lys_node *sibling, *start;
1521 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001522 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001523 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001524
1525 assert(nodeid && module && ret);
1526 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1527
1528 id = nodeid;
1529 start = module->data;
1530
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001531 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 +01001532 return ((id - nodeid) - r) + 1;
1533 }
1534 id += r;
1535
1536 if (is_relative) {
1537 return -1;
1538 }
1539
1540 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001541 if (!abs_start_mod) {
1542 return -1;
1543 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001544
1545 while (1) {
1546 sibling = NULL;
1547 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1548 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1549 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001550 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001551 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1552 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001553 if (!(sibling->nodetype & ret_nodetype)) {
1554 /* wrong node type, too bad */
1555 continue;
1556 }
1557 *ret = sibling;
1558 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001559 } else if (r == 1) {
1560 continue;
1561 } else if (r == 2) {
1562 break;
1563 } else {
1564 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001565 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001566 }
1567 }
1568
1569 /* no match */
1570 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001571 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001572 return EXIT_SUCCESS;
1573 }
1574
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001575 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 +01001576 return ((id - nodeid) - r) + 1;
1577 }
1578 id += r;
1579 }
1580
1581 /* cannot get here */
1582 LOGINT;
1583 return -1;
1584}
1585
Michal Vaskoe733d682016-03-14 09:08:27 +01001586static int
Michal Vasko3547c532016-03-14 09:40:50 +01001587resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001588{
1589 const char *name;
1590 int nam_len, has_predicate, i;
1591
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001592 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1593 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001594 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001595 return -1;
1596 }
1597
1598 predicate += i;
1599 *parsed += i;
1600
1601 for (i = 0; i < list->keys_size; ++i) {
1602 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1603 break;
1604 }
1605 }
1606
1607 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001608 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001609 return -1;
1610 }
1611
1612 /* more predicates? */
1613 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001614 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001615 }
1616
1617 return 0;
1618}
1619
Michal Vasko9fd98e22016-04-07 15:44:19 +02001620/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly
1621 * data_nodeid - 0 schema nodeid, 1 - data nodeid with RPC input, 2 - data nodeid with RPC output */
Michal Vaskoe733d682016-03-14 09:08:27 +01001622const struct lys_node *
Michal Vasko9fd98e22016-04-07 15:44:19 +02001623resolve_json_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int data_nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001624{
Michal Vasko10728b52016-04-07 14:26:29 +02001625 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001626 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001627 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001628 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001629 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001630 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001631
Michal Vasko3547c532016-03-14 09:40:50 +01001632 assert(nodeid && (ctx || start));
1633 if (!ctx) {
1634 ctx = start->module->ctx;
1635 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001636
1637 id = nodeid;
1638
Michal Vaskoe733d682016-03-14 09:08:27 +01001639 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 +01001640 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001641 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001642 }
1643 id += r;
1644
1645 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001646 assert(start);
1647 start = start->child;
1648 if (!start) {
1649 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001650 str = strndup(nodeid, (name + nam_len) - nodeid);
1651 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1652 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001653 return NULL;
1654 }
1655 module = start->module;
1656 } else {
1657 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001658 str = strndup(nodeid, (name + nam_len) - nodeid);
1659 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1660 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001661 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001662 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1663 LOGINT;
1664 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001665 }
1666
Michal Vasko971a3ca2016-04-01 13:09:29 +02001667 if (ly_buf_used && module_name[0]) {
1668 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1669 }
1670 ly_buf_used++;
1671
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001672 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001673 module_name[mod_name_len] = '\0';
1674 module = ly_ctx_get_module(ctx, module_name, NULL);
1675
1676 if (buf_backup) {
1677 /* return previous internal buffer content */
1678 strcpy(module_name, buf_backup);
1679 free(buf_backup);
1680 buf_backup = NULL;
1681 }
1682 ly_buf_used--;
1683
Michal Vasko3547c532016-03-14 09:40:50 +01001684 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001685 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1686 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1687 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001688 return NULL;
1689 }
1690 start = module->data;
1691
1692 /* now it's as if there was no module name */
1693 mod_name = NULL;
1694 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001695 }
1696
Michal Vaskoe733d682016-03-14 09:08:27 +01001697 prev_mod = module;
1698
Michal Vasko3edeaf72016-02-11 13:17:43 +01001699 while (1) {
1700 sibling = NULL;
Michal Vasko9fd98e22016-04-07 15:44:19 +02001701 while ((sibling = lys_getnext(sibling, lys_parent(start), module, (data_nodeid ?
1702 0 : LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT)))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001703 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001704 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001705
1706 /* data RPC input/output check */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001707 if ((data_nodeid == 1) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_OUTPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001708 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001709 } else if ((data_nodeid == 2) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_INPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001710 continue;
1711 }
1712
Michal Vasko3edeaf72016-02-11 13:17:43 +01001713 /* module check */
1714 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001715 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01001716 LOGINT;
1717 return NULL;
1718 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001719
1720 if (ly_buf_used && module_name[0]) {
1721 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1722 }
1723 ly_buf_used++;
1724
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001725 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01001726 module_name[mod_name_len] = '\0';
1727 /* will also find an augment module */
1728 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001729
1730 if (buf_backup) {
1731 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001732 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001733 free(buf_backup);
1734 buf_backup = NULL;
1735 }
1736 ly_buf_used--;
1737
Michal Vasko3edeaf72016-02-11 13:17:43 +01001738 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001739 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1740 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1741 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001742 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001743 }
1744 } else {
1745 prefix_mod = prev_mod;
1746 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001747 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001748 continue;
1749 }
1750
Michal Vaskoe733d682016-03-14 09:08:27 +01001751 /* do we have some predicates on it? */
1752 if (has_predicate) {
1753 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001754 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1755 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
1756 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1757 return NULL;
1758 }
1759 } else if (sibling->nodetype == LYS_LIST) {
1760 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
1761 return NULL;
1762 }
1763 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01001764 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001765 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01001766 }
1767 id += r;
1768 }
1769
Radek Krejcibdf92362016-04-08 14:43:34 +02001770 /* check for shorthand cases - then 'start' does not change */
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001771 if (!data_nodeid && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001772 shorthand = ~shorthand;
1773 }
1774
Michal Vasko3edeaf72016-02-11 13:17:43 +01001775 /* the result node? */
1776 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001777 if (shorthand) {
1778 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02001779 str = strndup(nodeid, (name + nam_len) - nodeid);
1780 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001781 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02001782 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02001783 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02001784 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001785 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001786 }
1787
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001788 if (data_nodeid || !shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001789 /* move down the tree, if possible */
1790 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001791 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01001792 return NULL;
1793 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001794 start = sibling->child;
1795 }
1796
1797 /* update prev mod */
1798 prev_mod = start->module;
1799 break;
1800 }
1801 }
1802
1803 /* no match */
1804 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02001805 str = strndup(nodeid, (name + nam_len) - nodeid);
1806 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1807 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001808 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001809 }
1810
Michal Vaskoe733d682016-03-14 09:08:27 +01001811 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 +01001812 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001813 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001814 }
1815 id += r;
1816 }
1817
1818 /* cannot get here */
1819 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001820 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001821}
1822
Michal Vasko22448d32016-03-16 13:17:29 +01001823static int
1824resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
1825{
1826 const char *name, *value;
1827 int nam_len, val_len, has_predicate = 1, r;
1828 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02001829 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01001830
Radek Krejci61a86c62016-03-24 11:06:44 +01001831 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01001832 assert(node->schema->nodetype == LYS_LIST);
1833
Michal Vaskof29903d2016-04-18 13:13:10 +02001834 key = (struct lyd_node_leaf_list *)node->child;
1835 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
1836 if (!key) {
1837 /* invalid data */
1838 LOGINT;
1839 return -1;
1840 }
Michal Vasko22448d32016-03-16 13:17:29 +01001841
Michal Vasko22448d32016-03-16 13:17:29 +01001842 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001843 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02001844 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001845 }
1846
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001847 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
1848 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001849 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02001850 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001851 }
1852
1853 predicate += r;
1854 *parsed += r;
1855
Michal Vaskof29903d2016-04-18 13:13:10 +02001856 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001857 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02001858 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001859 }
1860
1861 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02001862 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01001863 return 1;
1864 }
Michal Vaskof29903d2016-04-18 13:13:10 +02001865
1866 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01001867 }
1868
1869 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001870 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01001871 return -1;
1872 }
1873
1874 return 0;
1875}
1876
1877struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001878resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
1879 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01001880{
Michal Vasko10728b52016-04-07 14:26:29 +02001881 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01001882 const char *id, *mod_name, *name;
1883 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001884 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001885 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01001886 const struct lys_module *prefix_mod, *prev_mod;
1887 struct ly_ctx *ctx;
1888
1889 assert(nodeid && start && parsed);
1890
1891 ctx = start->schema->module->ctx;
1892 id = nodeid;
1893
1894 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 +01001895 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001896 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001897 return NULL;
1898 }
1899 id += r;
1900 /* add it to parsed only after the data node was actually found */
1901 last_parsed = r;
1902
1903 if (is_relative) {
1904 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01001905 start = start->child;
1906 } else {
1907 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01001908 prev_mod = start->schema->module;
1909 }
1910
1911 while (1) {
1912 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01001913 /* RPC data check, return simply invalid argument, because the data tree is invalid */
1914 if (lys_parent(sibling->schema)) {
1915 if (options & LYD_PATH_OPT_OUTPUT) {
1916 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02001917 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01001918 *parsed = -1;
1919 return NULL;
1920 }
1921 } else {
1922 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02001923 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01001924 *parsed = -1;
1925 return NULL;
1926 }
1927 }
1928 }
1929
Michal Vasko22448d32016-03-16 13:17:29 +01001930 /* name match */
1931 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
1932
1933 /* module check */
1934 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001935 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01001936 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001937 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001938 return NULL;
1939 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001940
1941 if (ly_buf_used && module_name[0]) {
1942 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1943 }
1944 ly_buf_used++;
1945
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001946 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01001947 module_name[mod_name_len] = '\0';
1948 /* will also find an augment module */
1949 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001950
1951 if (buf_backup) {
1952 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001953 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001954 free(buf_backup);
1955 buf_backup = NULL;
1956 }
1957 ly_buf_used--;
1958
Michal Vasko22448d32016-03-16 13:17:29 +01001959 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001960 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1961 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1962 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001963 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001964 return NULL;
1965 }
1966 } else {
1967 prefix_mod = prev_mod;
1968 }
1969 if (prefix_mod != lys_node_module(sibling->schema)) {
1970 continue;
1971 }
1972
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001973 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01001974 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001975 llist = (struct lyd_node_leaf_list *)sibling;
1976 if ((!llist_value && llist->value_str && llist->value_str[0])
1977 || (llist_value && strcmp(llist_value, llist->value_str))) {
1978 continue;
1979 }
Michal Vasko22448d32016-03-16 13:17:29 +01001980 }
1981
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001982 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01001983 if (sibling->schema->nodetype == LYS_LIST) {
1984 r = 0;
1985 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001986 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001987 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001988 return NULL;
1989 }
1990 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
1991 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01001992 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001993 return NULL;
1994 } else if (ret == 1) {
1995 /* this list instance does not match */
1996 continue;
1997 }
1998 id += r;
1999 last_parsed += r;
2000 }
2001
2002 *parsed += last_parsed;
2003
2004 /* the result node? */
2005 if (!id[0]) {
2006 return sibling;
2007 }
2008
2009 /* move down the tree, if possible */
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002010 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002011 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002012 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002013 return NULL;
2014 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002015 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002016 start = sibling->child;
2017 if (start) {
2018 prev_mod = start->schema->module;
2019 }
2020 break;
2021 }
2022 }
2023
2024 /* no match, return last match */
2025 if (!sibling) {
2026 return last_match;
2027 }
2028
2029 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 +01002030 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002031 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002032 return NULL;
2033 }
2034 id += r;
2035 last_parsed = r;
2036 }
2037
2038 /* cannot get here */
2039 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002040 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002041 return NULL;
2042}
2043
Michal Vasko3edeaf72016-02-11 13:17:43 +01002044/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002045 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002046 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002047 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002048 * @param[in] str_restr Restriction as a string.
2049 * @param[in] type Type of the restriction.
2050 * @param[out] ret Final interval structure that starts with
2051 * the interval of the initial type, continues with intervals
2052 * of any superior types derived from the initial one, and
2053 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002054 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002055 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002056 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002057int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002058resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002059{
2060 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002061 int kind;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002062 int64_t local_smin, local_smax;
2063 uint64_t local_umin, local_umax;
2064 long double local_fmin, local_fmax;
2065 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002066 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002067
2068 switch (type->base) {
2069 case LY_TYPE_BINARY:
2070 kind = 0;
2071 local_umin = 0;
2072 local_umax = 18446744073709551615UL;
2073
2074 if (!str_restr && type->info.binary.length) {
2075 str_restr = type->info.binary.length->expr;
2076 }
2077 break;
2078 case LY_TYPE_DEC64:
2079 kind = 2;
Radek Krejci8c3b4b62016-06-17 14:32:12 +02002080 local_fmin = ((long double)-9223372036854775808.0) / type->info.dec64.div;
2081 local_fmax = ((long double)9223372036854775807.0) / type->info.dec64.div;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002082
2083 if (!str_restr && type->info.dec64.range) {
2084 str_restr = type->info.dec64.range->expr;
2085 }
2086 break;
2087 case LY_TYPE_INT8:
2088 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002089 local_smin = __INT64_C(-128);
2090 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002091
2092 if (!str_restr && type->info.num.range) {
2093 str_restr = type->info.num.range->expr;
2094 }
2095 break;
2096 case LY_TYPE_INT16:
2097 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002098 local_smin = __INT64_C(-32768);
2099 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002100
2101 if (!str_restr && type->info.num.range) {
2102 str_restr = type->info.num.range->expr;
2103 }
2104 break;
2105 case LY_TYPE_INT32:
2106 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002107 local_smin = __INT64_C(-2147483648);
2108 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002109
2110 if (!str_restr && type->info.num.range) {
2111 str_restr = type->info.num.range->expr;
2112 }
2113 break;
2114 case LY_TYPE_INT64:
2115 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002116 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2117 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002118
2119 if (!str_restr && type->info.num.range) {
2120 str_restr = type->info.num.range->expr;
2121 }
2122 break;
2123 case LY_TYPE_UINT8:
2124 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002125 local_umin = __UINT64_C(0);
2126 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002127
2128 if (!str_restr && type->info.num.range) {
2129 str_restr = type->info.num.range->expr;
2130 }
2131 break;
2132 case LY_TYPE_UINT16:
2133 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002134 local_umin = __UINT64_C(0);
2135 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002136
2137 if (!str_restr && type->info.num.range) {
2138 str_restr = type->info.num.range->expr;
2139 }
2140 break;
2141 case LY_TYPE_UINT32:
2142 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002143 local_umin = __UINT64_C(0);
2144 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002145
2146 if (!str_restr && type->info.num.range) {
2147 str_restr = type->info.num.range->expr;
2148 }
2149 break;
2150 case LY_TYPE_UINT64:
2151 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002152 local_umin = __UINT64_C(0);
2153 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002154
2155 if (!str_restr && type->info.num.range) {
2156 str_restr = type->info.num.range->expr;
2157 }
2158 break;
2159 case LY_TYPE_STRING:
2160 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002161 local_umin = __UINT64_C(0);
2162 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002163
2164 if (!str_restr && type->info.str.length) {
2165 str_restr = type->info.str.length->expr;
2166 }
2167 break;
2168 default:
2169 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002170 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002171 }
2172
2173 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002174 if (type->der) {
2175 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002176 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002177 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002178 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002179 assert(!intv || (intv->kind == kind));
2180 }
2181
2182 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002183 /* we do not have any restriction, return superior ones */
2184 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002185 return EXIT_SUCCESS;
2186 }
2187
2188 /* adjust local min and max */
2189 if (intv) {
2190 tmp_intv = intv;
2191
2192 if (kind == 0) {
2193 local_umin = tmp_intv->value.uval.min;
2194 } else if (kind == 1) {
2195 local_smin = tmp_intv->value.sval.min;
2196 } else if (kind == 2) {
2197 local_fmin = tmp_intv->value.fval.min;
2198 }
2199
2200 while (tmp_intv->next) {
2201 tmp_intv = tmp_intv->next;
2202 }
2203
2204 if (kind == 0) {
2205 local_umax = tmp_intv->value.uval.max;
2206 } else if (kind == 1) {
2207 local_smax = tmp_intv->value.sval.max;
2208 } else if (kind == 2) {
2209 local_fmax = tmp_intv->value.fval.max;
2210 }
2211 }
2212
2213 /* finally parse our restriction */
2214 seg_ptr = str_restr;
2215 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002216 if (!tmp_local_intv) {
2217 assert(!local_intv);
2218 local_intv = malloc(sizeof *local_intv);
2219 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002220 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002221 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002222 tmp_local_intv = tmp_local_intv->next;
2223 }
Michal Vasko253035f2015-12-17 16:58:13 +01002224 if (!tmp_local_intv) {
2225 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002226 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002227 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002228
2229 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002230 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002231 tmp_local_intv->next = NULL;
2232
2233 /* min */
2234 ptr = seg_ptr;
2235 while (isspace(ptr[0])) {
2236 ++ptr;
2237 }
2238 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2239 if (kind == 0) {
2240 tmp_local_intv->value.uval.min = atoll(ptr);
2241 } else if (kind == 1) {
2242 tmp_local_intv->value.sval.min = atoll(ptr);
2243 } else if (kind == 2) {
2244 tmp_local_intv->value.fval.min = atoll(ptr);
2245 }
2246
2247 if ((ptr[0] == '+') || (ptr[0] == '-')) {
2248 ++ptr;
2249 }
2250 while (isdigit(ptr[0])) {
2251 ++ptr;
2252 }
2253 } else if (!strncmp(ptr, "min", 3)) {
2254 if (kind == 0) {
2255 tmp_local_intv->value.uval.min = local_umin;
2256 } else if (kind == 1) {
2257 tmp_local_intv->value.sval.min = local_smin;
2258 } else if (kind == 2) {
2259 tmp_local_intv->value.fval.min = local_fmin;
2260 }
2261
2262 ptr += 3;
2263 } else if (!strncmp(ptr, "max", 3)) {
2264 if (kind == 0) {
2265 tmp_local_intv->value.uval.min = local_umax;
2266 } else if (kind == 1) {
2267 tmp_local_intv->value.sval.min = local_smax;
2268 } else if (kind == 2) {
2269 tmp_local_intv->value.fval.min = local_fmax;
2270 }
2271
2272 ptr += 3;
2273 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002274 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002275 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002276 }
2277
2278 while (isspace(ptr[0])) {
2279 ptr++;
2280 }
2281
2282 /* no interval or interval */
2283 if ((ptr[0] == '|') || !ptr[0]) {
2284 if (kind == 0) {
2285 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2286 } else if (kind == 1) {
2287 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2288 } else if (kind == 2) {
2289 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2290 }
2291 } else if (!strncmp(ptr, "..", 2)) {
2292 /* skip ".." */
2293 ptr += 2;
2294 while (isspace(ptr[0])) {
2295 ++ptr;
2296 }
2297
2298 /* max */
2299 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2300 if (kind == 0) {
2301 tmp_local_intv->value.uval.max = atoll(ptr);
2302 } else if (kind == 1) {
2303 tmp_local_intv->value.sval.max = atoll(ptr);
2304 } else if (kind == 2) {
2305 tmp_local_intv->value.fval.max = atoll(ptr);
2306 }
2307 } else if (!strncmp(ptr, "max", 3)) {
2308 if (kind == 0) {
2309 tmp_local_intv->value.uval.max = local_umax;
2310 } else if (kind == 1) {
2311 tmp_local_intv->value.sval.max = local_smax;
2312 } else if (kind == 2) {
2313 tmp_local_intv->value.fval.max = local_fmax;
2314 }
2315 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002316 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002317 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002318 }
2319 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002320 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002321 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002322 }
2323
2324 /* next segment (next OR) */
2325 seg_ptr = strchr(seg_ptr, '|');
2326 if (!seg_ptr) {
2327 break;
2328 }
2329 seg_ptr++;
2330 }
2331
2332 /* check local restrictions against superior ones */
2333 if (intv) {
2334 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002335 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002336
2337 while (tmp_local_intv && tmp_intv) {
2338 /* reuse local variables */
2339 if (kind == 0) {
2340 local_umin = tmp_local_intv->value.uval.min;
2341 local_umax = tmp_local_intv->value.uval.max;
2342
2343 /* it must be in this interval */
2344 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2345 /* this interval is covered, next one */
2346 if (local_umax <= tmp_intv->value.uval.max) {
2347 tmp_local_intv = tmp_local_intv->next;
2348 continue;
2349 /* ascending order of restrictions -> fail */
2350 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002351 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002352 }
2353 }
2354 } else if (kind == 1) {
2355 local_smin = tmp_local_intv->value.sval.min;
2356 local_smax = tmp_local_intv->value.sval.max;
2357
2358 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2359 if (local_smax <= tmp_intv->value.sval.max) {
2360 tmp_local_intv = tmp_local_intv->next;
2361 continue;
2362 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002363 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002364 }
2365 }
2366 } else if (kind == 2) {
2367 local_fmin = tmp_local_intv->value.fval.min;
2368 local_fmax = tmp_local_intv->value.fval.max;
2369
2370 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
2371 if (local_fmax <= tmp_intv->value.fval.max) {
2372 tmp_local_intv = tmp_local_intv->next;
2373 continue;
2374 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002375 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002376 }
2377 }
2378 }
2379
2380 tmp_intv = tmp_intv->next;
2381 }
2382
2383 /* some interval left uncovered -> fail */
2384 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002385 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002386 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002387 }
2388
Michal Vaskoaeb51802016-04-11 10:58:47 +02002389 /* append the local intervals to all the intervals of the superior types, return it all */
2390 if (intv) {
2391 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2392 tmp_intv->next = local_intv;
2393 } else {
2394 intv = local_intv;
2395 }
2396 *ret = intv;
2397
2398 return EXIT_SUCCESS;
2399
2400error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002401 while (intv) {
2402 tmp_intv = intv->next;
2403 free(intv);
2404 intv = tmp_intv;
2405 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002406 while (local_intv) {
2407 tmp_local_intv = local_intv->next;
2408 free(local_intv);
2409 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002410 }
2411
Michal Vaskoaeb51802016-04-11 10:58:47 +02002412 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002413}
2414
Michal Vasko730dfdf2015-08-11 14:48:05 +02002415/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002416 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2417 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002418 *
2419 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002420 * @param[in] mod_name Typedef name module name.
2421 * @param[in] module Main module.
2422 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002423 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002424 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002425 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002426 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002427int
Michal Vasko1e62a092015-12-01 12:27:20 +01002428resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2429 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002430{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002431 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002432 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002433 int tpdf_size;
2434
Michal Vasko1dca6882015-10-22 14:29:42 +02002435 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002436 /* no prefix, try built-in types */
2437 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2438 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002439 if (ret) {
2440 *ret = ly_types[i].def;
2441 }
2442 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002443 }
2444 }
2445 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002446 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002447 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002448 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002449 }
2450 }
2451
Michal Vasko1dca6882015-10-22 14:29:42 +02002452 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002453 /* search in local typedefs */
2454 while (parent) {
2455 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002456 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002457 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2458 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002459 break;
2460
Radek Krejci76512572015-08-04 09:47:08 +02002461 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002462 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2463 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002464 break;
2465
Radek Krejci76512572015-08-04 09:47:08 +02002466 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002467 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2468 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002469 break;
2470
Radek Krejci76512572015-08-04 09:47:08 +02002471 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02002472 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
2473 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002474 break;
2475
Radek Krejci76512572015-08-04 09:47:08 +02002476 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002477 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2478 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002479 break;
2480
Radek Krejci76512572015-08-04 09:47:08 +02002481 case LYS_INPUT:
2482 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02002483 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
2484 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002485 break;
2486
2487 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002488 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002489 continue;
2490 }
2491
2492 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002493 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002494 match = &tpdf[i];
2495 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002496 }
2497 }
2498
Michal Vaskodcf98e62016-05-05 17:53:53 +02002499 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002500 }
Radek Krejcic071c542016-01-27 14:57:51 +01002501 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002502 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002503 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002504 if (!module) {
2505 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002506 }
2507 }
2508
2509 /* search in top level typedefs */
2510 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002511 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002512 match = &module->tpdf[i];
2513 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002514 }
2515 }
2516
2517 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002518 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002519 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002520 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002521 match = &module->inc[i].submodule->tpdf[j];
2522 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523 }
2524 }
2525 }
2526
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002527 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002528
2529check_leafref:
2530 if (ret) {
2531 *ret = match;
2532 }
2533 if (match->type.base == LY_TYPE_LEAFREF) {
2534 while (!match->type.info.lref.path) {
2535 match = match->type.der;
2536 assert(match);
2537 }
2538 if (!match->type.info.lref.target) {
2539 /* lefref not resolved yet, not good enough */
2540 if (ret) {
2541 *ret = NULL;
2542 }
2543 return EXIT_FAILURE;
2544 }
2545 }
2546 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002547}
2548
Michal Vasko1dca6882015-10-22 14:29:42 +02002549/**
2550 * @brief Check the default \p value of the \p type. Logs directly.
2551 *
2552 * @param[in] type Type definition to use.
2553 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002554 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002555 *
2556 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2557 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002558static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002559check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002560{
Michal Vasko1dca6882015-10-22 14:29:42 +02002561 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002562 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002563
2564 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002565 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002566 node.value_str = value;
2567 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002568 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002569 if (!node.schema) {
2570 LOGMEM;
2571 return -1;
2572 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002573 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01002574 if (!node.schema->name) {
2575 LOGMEM;
2576 return -1;
2577 }
Michal Vasko56826402016-03-02 11:11:37 +01002578 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002579 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002580
Radek Krejci37b756f2016-01-18 10:15:03 +01002581 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002582 if (!type->info.lref.target) {
2583 ret = EXIT_FAILURE;
2584 goto finish;
2585 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002586 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002587
2588 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2589 /* it was converted to JSON format before, nothing else sensible we can do */
2590
2591 } else {
Radek Krejci0b7704f2016-03-18 12:16:14 +01002592 ret = lyp_parse_value(&node, NULL, 1);
Michal Vasko1dca6882015-10-22 14:29:42 +02002593 }
2594
2595finish:
2596 if (node.value_type == LY_TYPE_BITS) {
2597 free(node.value.bit);
2598 }
2599 free((char *)node.schema->name);
2600 free(node.schema);
2601
2602 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002603}
2604
Michal Vasko730dfdf2015-08-11 14:48:05 +02002605/**
2606 * @brief Check a key for mandatory attributes. Logs directly.
2607 *
2608 * @param[in] key The key to check.
2609 * @param[in] flags What flags to check.
2610 * @param[in] list The list of all the keys.
2611 * @param[in] index Index of the key in the key list.
2612 * @param[in] name The name of the keys.
2613 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002614 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002615 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002616 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002617static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002618check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002619{
Radek Krejciadb57612016-02-16 13:34:34 +01002620 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002621 char *dup = NULL;
2622 int j;
2623
2624 /* existence */
2625 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002626 if (name[len] != '\0') {
2627 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002628 if (!dup) {
2629 LOGMEM;
2630 return -1;
2631 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002632 dup[len] = '\0';
2633 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002634 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002635 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002636 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002637 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002638 }
2639
2640 /* uniqueness */
2641 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002642 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002643 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002644 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002645 }
2646 }
2647
2648 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002649 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002650 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002651 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002652 }
2653
2654 /* type of the leaf is not built-in empty */
2655 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002656 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002657 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002658 }
2659
2660 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002661 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002662 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002663 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002664 }
2665
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002666 /* key is not placed from augment */
2667 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002668 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
2669 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002670 return -1;
2671 }
2672
Michal Vaskocca47842016-03-17 10:31:07 +01002673 /* key is not when-conditional */
2674 if (key->when) {
Radek Krejci02a04992016-03-17 16:06:37 +01002675 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
2676 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
Radek Krejci581ce772015-11-10 17:22:40 +01002677 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002678 }
2679
Michal Vasko0b85aa82016-03-07 14:37:43 +01002680 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02002681}
Michal Vasko730dfdf2015-08-11 14:48:05 +02002682
2683/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002684 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002685 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002686 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002687 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002688 *
2689 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
2690 */
2691int
Radek Krejci48464ed2016-03-17 15:44:09 +01002692resolve_unique(struct lys_node *parent, const char *uniq_str_path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002693{
Radek Krejci581ce772015-11-10 17:22:40 +01002694 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002695 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002696
Radek Krejcif3c71de2016-04-11 12:45:46 +02002697 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002698 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002699 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002700 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002701 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002702 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02002703 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02002704 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01002705 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002706 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01002707 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01002708 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2709 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002710 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002711 }
Radek Krejci581ce772015-11-10 17:22:40 +01002712 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002713 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002714 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002715 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2716 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002717 rc = -1;
2718 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002719 }
2720
Radek Krejcicf509982015-12-15 09:22:44 +01002721 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01002722 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002723 return -1;
2724 }
2725
Radek Krejcica7efb72016-01-18 13:06:01 +01002726 /* set leaf's unique flag */
2727 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2728
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002729 return EXIT_SUCCESS;
2730
2731error:
2732
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002733 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002734}
2735
Radek Krejci0c0086a2016-03-24 15:20:28 +01002736void
Michal Vasko23b61ec2015-08-19 11:19:50 +02002737unres_data_del(struct unres_data *unres, uint32_t i)
2738{
2739 /* there are items after the one deleted */
2740 if (i+1 < unres->count) {
2741 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002742 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002743
2744 /* deleting the last item */
2745 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002746 free(unres->node);
2747 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002748 }
2749
2750 /* if there are no items after and it is not the last one, just move the counter */
2751 --unres->count;
2752}
2753
Michal Vasko0491ab32015-08-19 14:28:29 +02002754/**
2755 * @brief Resolve (find) a data node from a specific module. Does not log.
2756 *
2757 * @param[in] mod Module to search in.
2758 * @param[in] name Name of the data node.
2759 * @param[in] nam_len Length of the name.
2760 * @param[in] start Data node to start the search from.
2761 * @param[in,out] parents Resolved nodes. If there are some parents,
2762 * they are replaced (!!) with the resolvents.
2763 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02002764 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02002765 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002766static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002767resolve_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 +02002768{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002769 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002770 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002771 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002772
Michal Vasko23b61ec2015-08-19 11:19:50 +02002773 if (!parents->count) {
2774 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002775 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002776 if (!parents->node) {
2777 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02002778 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002779 }
Michal Vaskocf024702015-10-08 15:01:42 +02002780 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002781 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002782 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002783 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002785 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002786 continue;
2787 }
2788 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002789 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2791 && node->schema->name[nam_len] == '\0') {
2792 /* matching target */
2793 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002794 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002795 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 flag = 1;
2797 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002798 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002799 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002800 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2801 if (!parents->node) {
2802 return EXIT_FAILURE;
2803 }
Michal Vaskocf024702015-10-08 15:01:42 +02002804 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002805 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002806 }
2807 }
2808 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002809
2810 if (!flag) {
2811 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002812 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002813 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002814 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002815 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002816 }
2817
Michal Vasko0491ab32015-08-19 14:28:29 +02002818 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002819}
2820
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002821/**
2822 * @brief Resolve (find) a data node. Does not log.
2823 *
Radek Krejci581ce772015-11-10 17:22:40 +01002824 * @param[in] mod_name Module name of the data node.
2825 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002826 * @param[in] name Name of the data node.
2827 * @param[in] nam_len Length of the name.
2828 * @param[in] start Data node to start the search from.
2829 * @param[in,out] parents Resolved nodes. If there are some parents,
2830 * they are replaced (!!) with the resolvents.
2831 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002832 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002833 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002834static int
Radek Krejci581ce772015-11-10 17:22:40 +01002835resolve_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 +02002836 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002837{
Michal Vasko1e62a092015-12-01 12:27:20 +01002838 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002839 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002840
Michal Vasko23b61ec2015-08-19 11:19:50 +02002841 assert(start);
2842
Michal Vasko31fc3672015-10-21 12:08:13 +02002843 if (mod_name) {
2844 /* we have mod_name, find appropriate module */
2845 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002846 if (!str) {
2847 LOGMEM;
2848 return -1;
2849 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002850 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2851 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002852 if (!mod) {
2853 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002854 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002855 }
2856 } else {
2857 /* no prefix, module is the same as of current node */
2858 mod = start->schema->module;
2859 }
2860
2861 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862}
2863
Michal Vasko730dfdf2015-08-11 14:48:05 +02002864/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002865 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01002866 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002867 *
Michal Vaskobb211122015-08-19 14:03:11 +02002868 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002869 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002870 * @param[in,out] node_match Nodes satisfying the restriction
2871 * without the predicate. Nodes not
2872 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002873 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002874 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002875 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002876 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002878resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01002879 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002881 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002882 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002884 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2885 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002886 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02002887 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002888
2889 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002890 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002891 if (!source_match.node) {
2892 LOGMEM;
2893 return -1;
2894 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002895 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002896 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002897 if (!dest_match.node) {
2898 LOGMEM;
2899 return -1;
2900 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002901
2902 do {
2903 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2904 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002905 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002906 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002907 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002908 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002909 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002910 pred += i;
2911
Michal Vasko23b61ec2015-08-19 11:19:50 +02002912 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002914 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002915
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002917 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002918 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002919 i = 0;
2920 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002921 }
2922
2923 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02002924 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002925 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2927 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002928 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002929 rc = -1;
2930 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002932 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002934 dest_match.node[0] = dest_match.node[0]->parent;
2935 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002936 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002937 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002938 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939 }
2940 }
2941 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002942 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002943 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002944 i = 0;
2945 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002946 }
2947
2948 if (pke_len == pke_parsed) {
2949 break;
2950 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002951 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 +02002952 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002953 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002954 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002955 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002956 }
2957 pke_parsed += i;
2958 }
2959
2960 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02002961 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
2962 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
2963 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
2964 }
2965 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
2966 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
2967 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
2968 }
2969 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970 goto remove_leafref;
2971 }
2972
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02002973 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002974 goto remove_leafref;
2975 }
2976
2977 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002978 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002979 continue;
2980
2981remove_leafref:
2982 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002983 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002984 }
2985 } while (has_predicate);
2986
Michal Vaskocf024702015-10-08 15:01:42 +02002987 free(source_match.node);
2988 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002989 if (parsed) {
2990 *parsed = parsed_loc;
2991 }
2992 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002993
2994error:
2995
2996 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002997 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002998 }
2999 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003000 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003001 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003002 if (parsed) {
3003 *parsed = -parsed_loc+i;
3004 }
3005 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003006}
3007
Michal Vasko730dfdf2015-08-11 14:48:05 +02003008/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003009 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003010 *
Michal Vaskocf024702015-10-08 15:01:42 +02003011 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003012 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003013 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003014 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003015 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003016 */
Michal Vasko184521f2015-09-24 13:14:26 +02003017static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003018resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003019{
Radek Krejci71b795b2015-08-10 16:20:39 +02003020 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003021 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003022 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003023 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003024
Michal Vaskocf024702015-10-08 15:01:42 +02003025 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003026
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003028 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003029
3030 /* searching for nodeset */
3031 do {
3032 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003033 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003034 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003035 goto error;
3036 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003037 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003038 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003039
Michal Vasko23b61ec2015-08-19 11:19:50 +02003040 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02003041 if (parent_times != -1) {
3042 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003043 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003044 if (!ret->node) {
3045 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01003046 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003047 goto error;
3048 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02003049 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050 for (i = 0; i < parent_times; ++i) {
3051 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003052 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003053 /* error, too many .. */
Radek Krejci48464ed2016-03-17 15:44:09 +01003054 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02003055 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003056 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02003057 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003058 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02003059 data = ret->node[0] = node->parent;
3060 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003061 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003062 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003063 free(ret->node);
3064 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003065 } else {
3066 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02003067 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003068 }
3069 }
3070
3071 /* absolute path */
3072 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02003073 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003074 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02003075 if (data->prev) {
3076 for (; data->prev->next; data = data->prev);
3077 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003078 }
3079 }
3080
3081 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003082 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003083 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003084 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003085 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003086 goto error;
3087 }
3088
3089 if (has_predicate) {
3090 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003091 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003092 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3093 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003095 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003096 continue;
3097 }
3098
3099 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003100 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003101 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003102 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003103 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003104 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003105 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003106 goto error;
3107 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003108 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003109 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003110
Michal Vasko23b61ec2015-08-19 11:19:50 +02003111 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003112 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113 goto error;
3114 }
3115 }
3116 } while (path[0] != '\0');
3117
Michal Vaskof02e3742015-08-05 16:27:02 +02003118 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119
3120error:
3121
Michal Vaskocf024702015-10-08 15:01:42 +02003122 free(ret->node);
3123 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003124 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003125
Michal Vasko0491ab32015-08-19 14:28:29 +02003126 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127}
3128
Michal Vasko730dfdf2015-08-11 14:48:05 +02003129/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003130 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003131 *
Michal Vaskobb211122015-08-19 14:03:11 +02003132 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003133 * @param[in] context_node Predicate context node (where the predicate is placed).
3134 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003135 *
Michal Vasko184521f2015-09-24 13:14:26 +02003136 * @return 0 on forward reference, otherwise the number
3137 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003138 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003139 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003140static int
Radek Krejciadb57612016-02-16 13:34:34 +01003141resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01003142 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02003143{
Michal Vasko1e62a092015-12-01 12:27:20 +01003144 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003145 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3146 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003147 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003148
3149 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003150 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003151 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003152 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003153 return -parsed+i;
3154 }
3155 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003156 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003157
Michal Vasko58090902015-08-13 14:04:15 +02003158 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003159 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003160 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003161 }
Radek Krejciadb57612016-02-16 13:34:34 +01003162 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003163 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003164 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003165 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003166 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003167 }
3168
3169 /* destination */
3170 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3171 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003172 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 +02003173 return -parsed;
3174 }
3175 pke_parsed += i;
3176
Radek Krejciadb57612016-02-16 13:34:34 +01003177 /* parent is actually the parent of this leaf, so skip the first ".." */
3178 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003179 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003180 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003181 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003182 }
Michal Vaskodcf98e62016-05-05 17:53:53 +02003183 dst_node = lys_parent(dst_node);
Michal Vasko1f76a282015-08-04 16:16:53 +02003184 }
3185 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003186 if (!dest_pref) {
3187 dest_pref = dst_node->module->name;
3188 }
3189 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003190 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003191 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003192 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003193 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003194 }
3195
3196 if (pke_len == pke_parsed) {
3197 break;
3198 }
3199
3200 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3201 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003202 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003203 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003204 return -parsed;
3205 }
3206 pke_parsed += i;
3207 }
3208
3209 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02003210 if (dst_node->nodetype != LYS_LEAF) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003211 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Radek Krejci48464ed2016-03-17 15:44:09 +01003212 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
3213 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003214 return -parsed;
3215 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003216 } while (has_predicate);
3217
3218 return parsed;
3219}
3220
Michal Vasko730dfdf2015-08-11 14:48:05 +02003221/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003222 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003223 *
Michal Vaskobb211122015-08-19 14:03:11 +02003224 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003225 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003226 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3227 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003228 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003229 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003230 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003231 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003232static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003233resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003234 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003235{
Michal Vasko1e62a092015-12-01 12:27:20 +01003236 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01003237 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02003238 const char *id, *prefix, *name;
3239 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02003240 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003241
Michal Vasko184521f2015-09-24 13:14:26 +02003242 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003243 parent_times = 0;
3244 id = path;
3245
3246 do {
3247 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003248 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 +02003249 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003250 }
3251 id += i;
3252
Michal Vasko184521f2015-09-24 13:14:26 +02003253 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003254 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003255 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003256 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01003257 /* get start node */
3258 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003259 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003260 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3261 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003262 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003263 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003264 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02003265 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01003266 if (parent_tpdf) {
3267 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003268 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003269 return -1;
3270 }
3271
Radek Krejci08a11052016-06-13 15:14:30 +02003272 node = lys_parent(parent);
Michal Vasko58090902015-08-13 14:04:15 +02003273 i = 0;
3274 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003275 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003276 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3277 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003278 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003279 }
Michal Vasko58090902015-08-13 14:04:15 +02003280
3281 /* this node is a wrong node, we actually need the augment target */
3282 if (node->nodetype == LYS_AUGMENT) {
3283 node = ((struct lys_node_augment *)node)->target;
3284 if (!node) {
3285 continue;
3286 }
3287 }
3288
3289 ++i;
3290 if (i == parent_times) {
3291 break;
3292 }
Michal Vaskodcf98e62016-05-05 17:53:53 +02003293 node = lys_parent(node);
Michal Vasko1f76a282015-08-04 16:16:53 +02003294 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003295
Michal Vasko1f76a282015-08-04 16:16:53 +02003296 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02003297 } else {
3298 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003299 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003300 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003301
Michal Vasko184521f2015-09-24 13:14:26 +02003302 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003303 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003304 /* move down the tree, if possible */
3305 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003306 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 +01003307 return -1;
3308 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003309 node = node->child;
3310 }
3311
Michal Vasko4f0dad02016-02-15 14:08:23 +01003312 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003313 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003314 }
3315
Michal Vasko36cbaa42015-12-14 13:15:48 +01003316 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 +02003317 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003318 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003319 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003320 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003321
3322 if (has_predicate) {
3323 /* we have predicate, so the current result must be list */
3324 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003325 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003326 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003327 }
3328
Radek Krejci48464ed2016-03-17 15:44:09 +01003329 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003330 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003331 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003332 } else if (i < 0) {
3333 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003334 }
3335 id += i;
3336 }
3337 } while (id[0]);
3338
Radek Krejcib1c12512015-08-11 11:22:04 +02003339 /* the target must be leaf or leaf-list */
3340 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003341 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003342 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003343 }
3344
Radek Krejcicf509982015-12-15 09:22:44 +01003345 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003346 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003347 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003348 return -1;
3349 }
3350
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003351 if (ret) {
3352 *ret = node;
3353 }
3354 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003355}
3356
Michal Vasko730dfdf2015-08-11 14:48:05 +02003357/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003358 * @brief Resolve instance-identifier predicate in JSON data format.
3359 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003360 *
Michal Vaskobb211122015-08-19 14:03:11 +02003361 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003362 * @param[in,out] node_match Nodes matching the restriction without
3363 * the predicate. Nodes not satisfying
3364 * the predicate are removed.
3365 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003366 * @return Number of characters successfully parsed,
3367 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003368 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003370resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003372 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003373 struct unres_data target_match;
3374 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003375 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003376 const char *model, *name, *value;
3377 char *str;
3378 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3379 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380
Michal Vasko1f2cc332015-08-19 11:18:32 +02003381 assert(pred && node_match->count);
3382
Michal Vaskocf024702015-10-08 15:01:42 +02003383 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 idx = -1;
3385 parsed = 0;
3386
3387 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003388 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 return -parsed+i;
3390 }
3391 parsed += i;
3392 pred += i;
3393
Michal Vasko1f2cc332015-08-19 11:18:32 +02003394 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003395 if (isdigit(name[0])) {
3396 idx = atoi(name);
3397 }
3398
Michal Vasko1f2cc332015-08-19 11:18:32 +02003399 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003401 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003403 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003404 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003405 if (!target_match.node) {
3406 LOGMEM;
3407 return -1;
3408 }
Michal Vaskocf024702015-10-08 15:01:42 +02003409 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003410 } else {
3411 str = strndup(model, mod_len);
3412 mod = ly_ctx_get_module(ctx, str, NULL);
3413 free(str);
3414
Radek Krejci804836a2016-02-03 10:39:55 +01003415 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003416 goto remove_instid;
3417 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 }
3419
3420 /* check that we have the correct type */
3421 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003422 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 goto remove_instid;
3424 }
3425 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003426 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 goto remove_instid;
3428 }
3429 }
3430
Michal Vasko83a6c462015-10-08 16:43:53 +02003431 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3432 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003433 || (!value && (idx != cur_idx))) {
3434 goto remove_instid;
3435 }
3436
Michal Vaskocf024702015-10-08 15:01:42 +02003437 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438
3439 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003440 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441 continue;
3442
3443remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003444 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445
3446 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003447 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003448 }
3449 } while (has_predicate);
3450
3451 return parsed;
3452}
3453
Michal Vasko730dfdf2015-08-11 14:48:05 +02003454/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003455 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003456 *
Radek Krejciadb57612016-02-16 13:34:34 +01003457 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003459 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003460 * @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 +02003461 */
Michal Vasko184521f2015-09-24 13:14:26 +02003462static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003463resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003464{
Radek Krejcic5090c32015-08-12 09:46:19 +02003465 int i = 0, j;
3466 struct lyd_node *result = NULL;
Michal Vaskobea08e92016-05-18 13:28:08 +02003467 const struct lys_module *mod, *prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003468 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003469 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003470 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003471 int mod_len, name_len, has_predicate;
3472 struct unres_data node_match;
3473 uint32_t k;
3474
3475 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476
Radek Krejcic5090c32015-08-12 09:46:19 +02003477 /* we need root to resolve absolute path */
3478 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003479 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003480 if (data->prev) {
3481 for (; data->prev->next; data = data->prev);
3482 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483
Michal Vaskobea08e92016-05-18 13:28:08 +02003484 prev_mod = lyd_node_module(data);
3485
Radek Krejcic5090c32015-08-12 09:46:19 +02003486 /* search for the instance node */
3487 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003488 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003489 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003490 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 goto error;
3492 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003493 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003494
Michal Vaskobea08e92016-05-18 13:28:08 +02003495 if (model) {
3496 str = strndup(model, mod_len);
3497 if (!str) {
3498 LOGMEM;
3499 goto error;
3500 }
3501 mod = ly_ctx_get_module(ctx, str, NULL);
3502 free(str);
3503 } else {
3504 mod = prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003505 }
3506
Michal Vasko1f2cc332015-08-19 11:18:32 +02003507 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003508 /* no instance exists */
3509 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510 }
3511
3512 if (has_predicate) {
3513 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003514 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003515 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3516 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3517 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003518 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003519 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 continue;
3521 }
3522
3523 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003524 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003525 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003526
Michal Vaskof39142b2015-10-21 11:40:05 +02003527 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003528 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003529 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003530 goto error;
3531 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003532 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003533
Michal Vasko1f2cc332015-08-19 11:18:32 +02003534 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003535 /* no instance exists */
3536 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003537 }
3538 }
Michal Vaskobea08e92016-05-18 13:28:08 +02003539
3540 prev_mod = mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541 }
3542
Michal Vasko1f2cc332015-08-19 11:18:32 +02003543 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003544 /* no instance exists */
3545 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003547 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003548 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003549
Michal Vaskod6adbaa2016-04-11 11:01:09 +02003550 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003551 } else {
3552 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003553 result = node_match.node[0];
3554 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003555
3556 return result;
3557 }
3558
3559error:
3560
3561 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003562 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003563
3564 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565}
3566
Michal Vasko730dfdf2015-08-11 14:48:05 +02003567/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003568 * @brief Passes config flag down to children, skips nodes without config flags.
3569 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003570 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003571 * @param[in] node Siblings and their children to have flags changed.
3572 * @param[in] flags Flags to assign to all the nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003573 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003574static void
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003575inherit_config_flag(struct lys_node *node, int flags)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003577 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02003578 LY_TREE_FOR(node, node) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003579 if (node->flags & LYS_CONFIG_SET) {
3580 /* skip nodes with an explicit config value */
3581 continue;
3582 }
3583 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
Radek Krejci43f548d2016-06-16 11:06:38 +02003584 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003585 }
3586 inherit_config_flag(node->child, flags);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587 }
3588}
3589
Michal Vasko730dfdf2015-08-11 14:48:05 +02003590/**
Michal Vasko7178e692016-02-12 15:58:05 +01003591 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003592 *
Michal Vaskobb211122015-08-19 14:03:11 +02003593 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003594 * @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 +02003595 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003596 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003597 */
Michal Vasko7178e692016-02-12 15:58:05 +01003598static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003599resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003600{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003601 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003602 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003603
Michal Vasko1d87a922015-08-21 12:57:16 +02003604 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003605
3606 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003607 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), (const struct lys_node **)&aug->target);
Michal Vasko7178e692016-02-12 15:58:05 +01003608 if (rc == -1) {
3609 return -1;
3610 }
3611 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003612 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003613 return -1;
3614 }
3615 if (!aug->target) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003616 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003617 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003618 }
3619
3620 if (!aug->child) {
3621 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003622 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 return EXIT_SUCCESS;
3624 }
3625
Michal Vaskod58d5962016-03-02 14:29:41 +01003626 /* check for mandatory nodes - if the target node is in another module
3627 * the added nodes cannot be mandatory
3628 */
3629 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3630 && lyp_check_mandatory((struct lys_node *)aug)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003631 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
3632 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "When augmenting data in another module, mandatory nodes are not allowed.");
Michal Vaskod58d5962016-03-02 14:29:41 +01003633 return -1;
3634 }
3635
Michal Vasko07e89ef2016-03-03 13:28:57 +01003636 /* check augment target type and then augment nodes type */
3637 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3638 LY_TREE_FOR(aug->child, sub) {
3639 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003640 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3641 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003642 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3643 return -1;
3644 }
3645 }
3646 } else if (aug->target->nodetype == LYS_CHOICE) {
3647 LY_TREE_FOR(aug->child, sub) {
3648 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003649 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3650 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003651 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3652 return -1;
3653 }
3654 }
3655 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003656 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3657 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003658 return -1;
3659 }
3660
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003661 /* inherit config information from actual parent */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003663 inherit_config_flag(sub, aug->target->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664 }
3665
Radek Krejcic071c542016-01-27 14:57:51 +01003666 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003667 LY_TREE_FOR(aug->child, sub) {
Michal Vasko2afc1ca2016-05-03 11:38:53 +02003668 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003669 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003670 }
3671 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003672 /* reconnect augmenting data into the target - add them to the target child list */
3673 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003674 sub = aug->target->child->prev; /* remember current target's last node */
3675 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003676 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003677 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003678 } else {
3679 aug->target->child = aug->child;
3680 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003681
3682 return EXIT_SUCCESS;
3683}
3684
Michal Vasko730dfdf2015-08-11 14:48:05 +02003685/**
3686 * @brief Resolve uses, apply augments, refines. Logs directly.
3687 *
Michal Vaskobb211122015-08-19 14:03:11 +02003688 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003689 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003690 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003691 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003692 */
Michal Vasko184521f2015-09-24 13:14:26 +02003693static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003694resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695{
3696 struct ly_ctx *ctx;
Radek Krejci989790c2016-04-14 17:49:41 +02003697 struct lys_node *node = NULL, *next, *iter;
Radek Krejcia881e3e2016-06-23 17:02:39 +02003698 struct lys_node *node_aux, *parent;
Radek Krejci76512572015-08-04 09:47:08 +02003699 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003700 struct lys_restr *must, **old_must;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003701 int i, j, rc, parent_flags;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003702 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003703
Michal Vasko71e1aa82015-08-12 12:17:51 +02003704 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003705 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003706 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003707
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003708 if (!uses->grp->child) {
3709 /* grouping without children, warning was already displayed */
3710 return EXIT_SUCCESS;
3711 }
3712
3713 /* get proper parent (config) flags */
3714 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
3715 if (node_aux) {
3716 parent_flags = node_aux->flags & LYS_CONFIG_MASK;
3717 } else {
3718 /* default */
3719 parent_flags = LYS_CONFIG_W;
3720 }
3721
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003722 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003723 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003724 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, 0, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003725 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003726 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3727 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003728 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003729 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003730 }
3731 ctx = uses->module->ctx;
3732
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003733 if (parent_flags) {
3734 assert(uses->child);
3735 inherit_config_flag(uses->child, parent_flags);
3736 }
3737
Michal Vaskodef0db12015-10-07 13:22:48 +02003738 /* we managed to copy the grouping, the rest must be possible to resolve */
3739
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003740 /* apply refines */
3741 for (i = 0; i < uses->refine_size; i++) {
3742 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003743 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02003744 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003745 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003746 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003747 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003748 }
3749
Radek Krejci1d82ef62015-08-07 14:44:40 +02003750 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003751 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3752 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003753 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003754 }
3755
3756 /* description on any nodetype */
3757 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003758 lydict_remove(ctx, node->dsc);
3759 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003760 }
3761
3762 /* reference on any nodetype */
3763 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003764 lydict_remove(ctx, node->ref);
3765 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003766 }
3767
3768 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003769 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejcia881e3e2016-06-23 17:02:39 +02003770 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
3771 if (parent && parent->nodetype != LYS_GROUPING &&
3772 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
Radek Krejci989790c2016-04-14 17:49:41 +02003773 (rfn->flags & LYS_CONFIG_W)) {
3774 /* setting config true under config false is prohibited */
3775 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
3776 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
3777 "changing config from 'false' to 'true' is prohibited while "
3778 "the target's parent is still config 'false'.");
3779 return -1;
3780 }
3781
Radek Krejci1d82ef62015-08-07 14:44:40 +02003782 node->flags &= ~LYS_CONFIG_MASK;
3783 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Radek Krejci989790c2016-04-14 17:49:41 +02003784
3785 /* inherit config change to the target children */
3786 LY_TREE_DFS_BEGIN(node->child, next, iter) {
3787 if (rfn->flags & LYS_CONFIG_W) {
3788 if (iter->flags & LYS_CONFIG_SET) {
3789 /* config is set explicitely, go to next sibling */
3790 next = NULL;
3791 goto nextsibling;
3792 }
3793 } else { /* LYS_CONFIG_R */
3794 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
3795 /* error - we would have config data under status data */
3796 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
3797 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
3798 "changing config from 'true' to 'false' is prohibited while the target "
3799 "has still a children with explicit config 'true'.");
3800 return -1;
3801 }
3802 }
3803 /* change config */
3804 iter->flags &= ~LYS_CONFIG_MASK;
3805 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
3806
3807 /* select next iter - modified LY_TREE_DFS_END */
3808 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
3809 next = NULL;
3810 } else {
3811 next = iter->child;
3812 }
3813nextsibling:
3814 if (!next) {
3815 /* no children */
3816 if (iter == node->child) {
3817 /* we are done, (START) has no children */
3818 break;
3819 }
3820 /* try siblings */
3821 next = iter->next;
3822 }
3823 while (!next) {
3824 /* parent is already processed, go to its sibling */
3825 iter = lys_parent(iter);
3826
3827 /* no siblings, go back through parents */
3828 if (iter == node) {
3829 /* we are done, no next element to process */
3830 break;
3831 }
3832 next = iter->next;
3833 }
3834 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003835 }
3836
3837 /* default value ... */
3838 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003839 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003840 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003841 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3842 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3843 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003844 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003845 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3846 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003847 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003848 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003849 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003850 }
3851 }
3852 }
3853
3854 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003855 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003856 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003857 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003858 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003859
3860 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003861 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003862 }
3863 }
3864
3865 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003866 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3867 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3868 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003869 }
3870
3871 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003872 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003873 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003874 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003875 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003876 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003877 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003878 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003879 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003880 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003881 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003882 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003883 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003884 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003885 }
3886 }
3887
3888 /* must in leaf, leaf-list, list, container or anyxml */
3889 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003890 switch (node->nodetype) {
3891 case LYS_LEAF:
3892 old_size = &((struct lys_node_leaf *)node)->must_size;
3893 old_must = &((struct lys_node_leaf *)node)->must;
3894 break;
3895 case LYS_LEAFLIST:
3896 old_size = &((struct lys_node_leaflist *)node)->must_size;
3897 old_must = &((struct lys_node_leaflist *)node)->must;
3898 break;
3899 case LYS_LIST:
3900 old_size = &((struct lys_node_list *)node)->must_size;
3901 old_must = &((struct lys_node_list *)node)->must;
3902 break;
3903 case LYS_CONTAINER:
3904 old_size = &((struct lys_node_container *)node)->must_size;
3905 old_must = &((struct lys_node_container *)node)->must;
3906 break;
3907 case LYS_ANYXML:
3908 old_size = &((struct lys_node_anyxml *)node)->must_size;
3909 old_must = &((struct lys_node_anyxml *)node)->must;
3910 break;
3911 default:
3912 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003913 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003914 }
3915
3916 size = *old_size + rfn->must_size;
3917 must = realloc(*old_must, size * sizeof *rfn->must);
3918 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003919 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003920 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003921 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003922 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3923 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3924 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3925 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3926 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3927 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003928 }
3929
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003930 *old_must = must;
3931 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003932 }
3933 }
3934
3935 /* apply augments */
3936 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003937 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003938 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003939 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003940 }
3941 }
3942
3943 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003944}
3945
Michal Vasko730dfdf2015-08-11 14:48:05 +02003946/**
3947 * @brief Resolve base identity recursively. Does not log.
3948 *
3949 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003950 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003951 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003952 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003953 *
Michal Vaskof2006002016-04-21 16:28:15 +02003954 * @return EXIT_SUCCESS on success (but ret can still be NULL), EXIT_FAILURE on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003955 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003956static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003957resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003958 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003959{
Michal Vaskof02e3742015-08-05 16:27:02 +02003960 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003961 struct lys_ident *base = NULL, *base_iter;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003962
Radek Krejcicf509982015-12-15 09:22:44 +01003963 assert(ret);
3964
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003965 /* search module */
3966 for (i = 0; i < module->ident_size; i++) {
3967 if (!strcmp(basename, module->ident[i].name)) {
3968
3969 if (!ident) {
3970 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003971 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003972 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003973 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003974 }
3975
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003976 base = &module->ident[i];
3977 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003978 }
3979 }
3980
3981 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003982 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3983 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3984 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003985
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003986 if (!ident) {
3987 *ret = &module->inc[j].submodule->ident[i];
3988 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003989 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003990
3991 base = &module->inc[j].submodule->ident[i];
3992 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003993 }
3994 }
3995 }
3996
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003997matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003998 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003999 if (base) {
4000 /* check for circular reference */
4001 for (base_iter = base; base_iter; base_iter = base_iter->base) {
4002 if (ident == base_iter) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004003 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
4004 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01004005 return EXIT_FAILURE;
4006 }
4007 }
4008 /* checks done, store the result */
4009 ident->base = base;
4010
4011 /* maintain backlinks to the derived identitise */
4012 while (base) {
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004013 /* 1. get current number of backlinks */
4014 if (base->der) {
4015 for (i = 0; base->der[i]; i++);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004016 } else {
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004017 i = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004018 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004019 base->der = ly_realloc(base->der, (i + 2) * sizeof *(base->der));
4020 if (!base->der) {
Michal Vasko253035f2015-12-17 16:58:13 +01004021 LOGMEM;
4022 return EXIT_FAILURE;
4023 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004024 base->der[i] = ident;
4025 base->der[i + 1] = NULL; /* array termination */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004026
Radek Krejcibabbff82016-02-19 13:31:37 +01004027 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004028 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004029
Radek Krejcicf509982015-12-15 09:22:44 +01004030 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004031 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004032 }
4033
Michal Vaskof2006002016-04-21 16:28:15 +02004034 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035}
4036
Michal Vasko730dfdf2015-08-11 14:48:05 +02004037/**
4038 * @brief Resolve base identity. Logs directly.
4039 *
4040 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004041 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004042 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004043 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004044 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004045 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004046 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004047 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004048static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004049resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejci48464ed2016-03-17 15:44:09 +01004050 struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051{
4052 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02004053 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01004054 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004055 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004056 struct lys_module *mod;
4057
4058 assert((ident && !type) || (!ident && type));
4059
4060 if (!type) {
4061 /* have ident to resolve */
4062 ret = &target;
4063 flags = ident->flags;
4064 mod = ident->module;
4065 } else {
4066 /* have type to fill */
4067 ret = &type->info.ident.ref;
4068 flags = type->parent->flags;
4069 mod = type->parent->module;
4070 }
Michal Vaskof2006002016-04-21 16:28:15 +02004071 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004072
4073 /* search for the base identity */
4074 name = strchr(basename, ':');
4075 if (name) {
4076 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004077 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004078 name++;
4079
Michal Vasko2d851a92015-10-20 16:16:36 +02004080 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004081 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004082 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004083 }
4084 } else {
4085 name = basename;
4086 }
4087
Radek Krejcic071c542016-01-27 14:57:51 +01004088 /* get module where to search */
4089 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4090 if (!module) {
4091 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004092 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004093 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004094 }
4095
Radek Krejcic071c542016-01-27 14:57:51 +01004096 /* search in the identified module ... */
Michal Vaskof2006002016-04-21 16:28:15 +02004097 if (resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcibabbff82016-02-19 13:31:37 +01004098 return EXIT_FAILURE;
Michal Vaskof2006002016-04-21 16:28:15 +02004099 } else if (*ret) {
4100 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004101 }
Radek Krejcic071c542016-01-27 14:57:51 +01004102 /* and all its submodules */
4103 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskof2006002016-04-21 16:28:15 +02004104 if (resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
Radek Krejcibabbff82016-02-19 13:31:37 +01004105 return EXIT_FAILURE;
Michal Vaskof2006002016-04-21 16:28:15 +02004106 } else if (*ret) {
4107 goto success;
Radek Krejcic071c542016-01-27 14:57:51 +01004108 }
4109 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004110
Michal Vaskof2006002016-04-21 16:28:15 +02004111 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004112 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01004113
4114success:
4115 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01004116 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4117 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004118 return -1;
4119 }
4120
4121 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004122}
4123
Michal Vasko730dfdf2015-08-11 14:48:05 +02004124/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004125 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004126 *
4127 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02004128 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01004129 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02004130 *
4131 * @return Pointer to the identity resolvent, NULL on error.
4132 */
Radek Krejcia52656e2015-08-05 13:41:50 +02004133struct lys_ident *
Radek Krejci48464ed2016-03-17 15:44:09 +01004134resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004135{
Michal Vaskoc633ca02015-08-21 14:03:51 +02004136 const char *mod_name, *name;
4137 int mod_name_len, rc;
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004138 int i;
4139 struct lys_ident *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004140
Michal Vaskofb0873c2015-08-21 09:00:07 +02004141 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004142 return NULL;
4143 }
4144
Michal Vaskoc633ca02015-08-21 14:03:51 +02004145 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004146 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004147 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004148 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004149 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01004150 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004151 return NULL;
4152 }
4153
Michal Vaskoc633ca02015-08-21 14:03:51 +02004154 if (!strcmp(base->name, name) && (!mod_name
4155 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02004156 return base;
4157 }
4158
Radek Krejci1b61d0e2016-04-15 13:55:44 +02004159 if (base->der) {
4160 for (der = base->der[i = 0]; base->der[i]; der = base->der[++i]) {
4161 if (!strcmp(der->name, name) &&
4162 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
4163 /* we have match */
4164 return der;
4165 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004166 }
4167 }
4168
Radek Krejci48464ed2016-03-17 15:44:09 +01004169 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004170 return NULL;
4171}
4172
Michal Vasko730dfdf2015-08-11 14:48:05 +02004173/**
Michal Vasko7955b362015-09-04 14:18:15 +02004174 * @brief Resolve (find) choice default case. Does not log.
4175 *
4176 * @param[in] choic Choice to use.
4177 * @param[in] dflt Name of the default case.
4178 *
4179 * @return Pointer to the default node or NULL.
4180 */
4181static struct lys_node *
4182resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4183{
4184 struct lys_node *child, *ret;
4185
4186 LY_TREE_FOR(choic->child, child) {
4187 if (child->nodetype == LYS_USES) {
4188 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4189 if (ret) {
4190 return ret;
4191 }
4192 }
4193
Radek Krejci749190d2016-02-18 16:26:25 +01004194 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02004195 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
4196 return child;
4197 }
4198 }
4199
4200 return NULL;
4201}
4202
4203/**
Michal Vaskobb211122015-08-19 14:03:11 +02004204 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004205 *
Michal Vaskobb211122015-08-19 14:03:11 +02004206 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004207 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004208 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004209 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004210 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004211static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004212resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004213{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004214 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01004215 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02004216
Radek Krejci010e54b2016-03-15 09:40:34 +01004217 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
4218 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
4219 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
4220 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
4221 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02004222 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 +02004223
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004224 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01004225 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
4226 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004227 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004228 return -1;
4229 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004230 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004231 return -1;
4232 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004233 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004234 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
4235 * (and smaller flags - it uses only a limited set of flags)
4236 */
4237 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004238 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004239 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01004240 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02004241 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004242 }
4243
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004244 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004245 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004246 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004247 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004248 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004249 return EXIT_FAILURE;
4250 }
4251
Radek Krejci48464ed2016-03-17 15:44:09 +01004252 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004253 if (!rc) {
4254 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01004255 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004256 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004257 LOGINT;
4258 return -1;
4259 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02004260 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01004261 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004262 }
Radek Krejcicf509982015-12-15 09:22:44 +01004263
4264 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004265 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01004266 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004267 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004268 return -1;
4269 }
4270
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004271 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004272 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004273 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004274 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004275 }
4276
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004277 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004278}
4279
Michal Vasko730dfdf2015-08-11 14:48:05 +02004280/**
Michal Vasko9957e592015-08-17 15:04:09 +02004281 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004282 *
Michal Vaskobb211122015-08-19 14:03:11 +02004283 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004284 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004285 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004286 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004287 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004288static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004289resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004290{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004291 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01004292 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004293
4294 for (i = 0; i < list->keys_size; ++i) {
4295 /* get the key name */
4296 if ((value = strpbrk(keys_str, " \t\n"))) {
4297 len = value - keys_str;
4298 while (isspace(value[0])) {
4299 value++;
4300 }
4301 } else {
4302 len = strlen(keys_str);
4303 }
4304
Radek Krejcic4283442016-04-22 09:19:27 +02004305 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 +02004306 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02004307 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
4308 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004309 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004310
Radek Krejci48464ed2016-03-17 15:44:09 +01004311 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004312 /* check_key logs */
4313 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004314 }
4315
Radek Krejcicf509982015-12-15 09:22:44 +01004316 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004317 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004318 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
4319 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01004320 return -1;
4321 }
4322
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004323 /* prepare for next iteration */
4324 while (value && isspace(value[0])) {
4325 value++;
4326 }
4327 keys_str = value;
4328 }
4329
Michal Vaskof02e3742015-08-05 16:27:02 +02004330 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004331}
4332
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004333/**
Michal Vaskobf19d252015-10-08 15:39:17 +02004334 * @brief Resolve (check) all must conditions of \p node.
4335 * Logs directly.
4336 *
4337 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02004338 *
4339 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
4340 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004341static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004342resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02004343{
Michal Vaskobf19d252015-10-08 15:39:17 +02004344 uint8_t i, must_size;
4345 struct lys_restr *must;
4346 struct lyxp_set set;
4347
4348 assert(node);
4349 memset(&set, 0, sizeof set);
4350
4351 switch (node->schema->nodetype) {
4352 case LYS_CONTAINER:
4353 must_size = ((struct lys_node_container *)node->schema)->must_size;
4354 must = ((struct lys_node_container *)node->schema)->must;
4355 break;
4356 case LYS_LEAF:
4357 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
4358 must = ((struct lys_node_leaf *)node->schema)->must;
4359 break;
4360 case LYS_LEAFLIST:
4361 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
4362 must = ((struct lys_node_leaflist *)node->schema)->must;
4363 break;
4364 case LYS_LIST:
4365 must_size = ((struct lys_node_list *)node->schema)->must_size;
4366 must = ((struct lys_node_list *)node->schema)->must;
4367 break;
4368 case LYS_ANYXML:
4369 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
4370 must = ((struct lys_node_anyxml *)node->schema)->must;
4371 break;
4372 default:
4373 must_size = 0;
4374 break;
4375 }
4376
4377 for (i = 0; i < must_size; ++i) {
Michal Vasko944a5642016-03-21 11:48:58 +01004378 if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004379 return -1;
4380 }
4381
Michal Vasko944a5642016-03-21 11:48:58 +01004382 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02004383
Michal Vasko8146d4c2016-05-09 15:50:29 +02004384 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02004385 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
4386 if (must[i].emsg) {
4387 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
4388 }
4389 if (must[i].eapptag) {
4390 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
4391 }
Michal Vaskobf19d252015-10-08 15:39:17 +02004392 return 1;
4393 }
4394 }
4395
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004396 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02004397}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004398
Michal Vaskobf19d252015-10-08 15:39:17 +02004399/**
Michal Vaskocf024702015-10-08 15:01:42 +02004400 * @brief Resolve (find) when condition context node. Does not log.
4401 *
4402 * @param[in] node Data node, whose conditional definition is being decided.
4403 * @param[in] schema Schema node with a when condition.
4404 *
4405 * @return Context node.
4406 */
4407static struct lyd_node *
4408resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004409{
Michal Vaskocf024702015-10-08 15:01:42 +02004410 struct lyd_node *parent;
4411 struct lys_node *sparent;
4412 uint16_t i, data_depth, schema_depth;
4413
4414 /* find a not schema-only node */
4415 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
4416 schema = lys_parent(schema);
4417 if (!schema) {
4418 return NULL;
4419 }
4420 }
4421
4422 /* get node depths */
4423 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
4424 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
4425 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
4426 ++schema_depth;
4427 }
4428 }
4429 if (data_depth < schema_depth) {
4430 return NULL;
4431 }
4432
4433 /* find the corresponding data node */
4434 for (i = 0; i < data_depth - schema_depth; ++i) {
4435 node = node->parent;
4436 }
4437 if (node->schema != schema) {
4438 return NULL;
4439 }
4440
4441 return node;
4442}
4443
Radek Krejci03b71f72016-03-16 11:10:09 +01004444int
Radek Krejci01696bf2016-03-18 13:19:36 +01004445resolve_applies_must(const struct lyd_node *node)
4446{
4447 switch (node->schema->nodetype) {
4448 case LYS_CONTAINER:
4449 return ((struct lys_node_container *)node->schema)->must_size;
4450 case LYS_LEAF:
4451 return ((struct lys_node_leaf *)node->schema)->must_size;
4452 case LYS_LEAFLIST:
4453 return ((struct lys_node_leaflist *)node->schema)->must_size;
4454 case LYS_LIST:
4455 return ((struct lys_node_list *)node->schema)->must_size;
4456 case LYS_ANYXML:
4457 return ((struct lys_node_anyxml *)node->schema)->must_size;
4458 default:
4459 return 0;
4460 }
4461}
4462
4463int
Radek Krejci03b71f72016-03-16 11:10:09 +01004464resolve_applies_when(const struct lyd_node *node)
4465{
4466 struct lys_node *parent;
4467
4468 assert(node);
4469
4470 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
4471 return 1;
4472 }
4473
4474 parent = node->schema;
4475 goto check_augment;
4476
4477 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4478 if (((struct lys_node_uses *)parent)->when) {
4479 return 1;
4480 }
4481check_augment:
4482
4483 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
4484 (((struct lys_node_augment *)parent->parent)->when))) {
4485
4486 }
4487 parent = lys_parent(parent);
4488 }
4489
4490 return 0;
4491}
4492
Michal Vaskocf024702015-10-08 15:01:42 +02004493/**
4494 * @brief Resolve (check) all when conditions relevant for \p node.
4495 * Logs directly.
4496 *
4497 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02004498 *
Radek Krejci03b71f72016-03-16 11:10:09 +01004499 * @return
4500 * -1 - error, ly_errno is set
4501 * 0 - true "when" statement
4502 * 0, ly_vecode = LYVE_NOCOND - false "when" statement
4503 * 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 +02004504 */
4505static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004506resolve_when(struct lyd_node *node)
Michal Vaskocf024702015-10-08 15:01:42 +02004507{
4508 struct lyd_node *ctx_node = NULL;
4509 struct lys_node *parent;
4510 struct lyxp_set set;
Radek Krejci51093642016-03-29 10:14:59 +02004511 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02004512
4513 assert(node);
4514 memset(&set, 0, sizeof set);
4515
4516 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko944a5642016-03-21 11:48:58 +01004517 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004518 if (rc) {
4519 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004520 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004521 }
Radek Krejci51093642016-03-29 10:14:59 +02004522 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004523 }
4524
Radek Krejci03b71f72016-03-16 11:10:09 +01004525 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01004526 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02004527 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004528 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004529 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004530 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004531 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004532 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004533 }
Radek Krejci51093642016-03-29 10:14:59 +02004534
4535 /* free xpath set content */
4536 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004537 }
4538
4539 parent = node->schema;
4540 goto check_augment;
4541
4542 /* check when in every schema node that affects node */
4543 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4544 if (((struct lys_node_uses *)parent)->when) {
4545 if (!ctx_node) {
4546 ctx_node = resolve_when_ctx_node(node, parent);
4547 if (!ctx_node) {
4548 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004549 rc = -1;
4550 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004551 }
4552 }
Michal Vasko944a5642016-03-21 11:48:58 +01004553 rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004554 if (rc) {
4555 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004556 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004557 }
Radek Krejci51093642016-03-29 10:14:59 +02004558 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004559 }
4560
Michal Vasko944a5642016-03-21 11:48:58 +01004561 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02004562 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004563 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004564 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004565 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004566 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004567 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004568 }
Radek Krejci51093642016-03-29 10:14:59 +02004569
4570 /* free xpath set content */
4571 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004572 }
4573
4574check_augment:
4575 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
4576 if (!ctx_node) {
4577 ctx_node = resolve_when_ctx_node(node, parent->parent);
4578 if (!ctx_node) {
4579 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004580 rc = -1;
4581 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004582 }
4583 }
Michal Vasko944a5642016-03-21 11:48:58 +01004584 rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004585 if (rc) {
4586 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004587 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004588 }
Radek Krejci51093642016-03-29 10:14:59 +02004589 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004590 }
4591
Michal Vasko944a5642016-03-21 11:48:58 +01004592 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004593
Michal Vasko8146d4c2016-05-09 15:50:29 +02004594 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004595 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004596 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004597 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004598 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004599 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004600 }
Radek Krejci51093642016-03-29 10:14:59 +02004601
4602 /* free xpath set content */
4603 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004604 }
4605
4606 parent = lys_parent(parent);
4607 }
4608
Radek Krejci0b7704f2016-03-18 12:16:14 +01004609 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01004610
Radek Krejci51093642016-03-29 10:14:59 +02004611cleanup:
4612
4613 /* free xpath set content */
4614 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
4615
4616 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004617}
4618
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004619/**
Michal Vaskobb211122015-08-19 14:03:11 +02004620 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004621 *
4622 * @param[in] mod Main module.
4623 * @param[in] item Item to resolve. Type determined by \p type.
4624 * @param[in] type Type of the unresolved item.
4625 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02004626 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004627 *
4628 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4629 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004630static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004631resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01004632 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004633{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004634 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci4f78b532016-02-17 13:43:00 +01004635 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02004636 struct lys_node *node;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004637 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004638
4639 struct lys_ident *ident;
4640 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004641 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01004642 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004643 struct yang_type *yang;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004644
4645 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004646 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004647 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004648 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004649 ident = item;
4650
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004651 rc = resolve_base_ident(mod, ident, expr, "identity", NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004652 break;
4653 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004654 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004655 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004656 stype = item;
4657
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004658 rc = resolve_base_ident(mod, NULL, expr, "type", stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004659 break;
4660 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02004661 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004662 stype = item;
4663
Radek Krejci2f12f852016-01-08 12:59:57 +01004664 /* HACK - when there is no parent, we are in top level typedef and in that
4665 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
4666 * know it via tpdf_flag */
4667 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01004668 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01004669 node = (struct lys_node *)stype->parent;
4670 }
4671
Radek Krejci48464ed2016-03-17 15:44:09 +01004672 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01004673 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02004674 if (!tpdf_flag && !rc) {
4675 assert(stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01004676 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02004677 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
4678 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01004679 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01004680 }
4681
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004682 break;
4683 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004684 /* parent */
4685 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004686 stype = item;
4687
Michal Vasko88c29542015-11-27 14:57:53 +01004688 /* HACK type->der is temporarily unparsed type statement */
4689 yin = (struct lyxml_elem *)stype->der;
4690 stype->der = NULL;
4691
Pavol Vicana0e4e672016-02-24 12:20:04 +01004692 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4693 yang = (struct yang_type *)yin;
4694 rc = yang_check_type(mod, node, yang, unres);
4695
4696 if (rc) {
Pavol Vican933aa5a2016-04-09 21:05:46 +02004697 if (rc == -1) {
4698 yang->type->base = yang->base;
4699 lydict_remove(mod->ctx, yang->name);
4700 free(yang);
4701 stype->der = NULL;
4702 } else {
4703 /* may try again later */
4704 stype->der = (struct lys_tpdf *)yang;
4705 }
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004706 } else {
4707 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02004708 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004709 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01004710 }
4711
Michal Vasko88c29542015-11-27 14:57:53 +01004712 } else {
Pavol Vicana0e4e672016-02-24 12:20:04 +01004713 rc = fill_yin_type(mod, node, yin, stype, unres);
4714 if (!rc) {
4715 /* we need to always be able to free this, it's safe only in this case */
4716 lyxml_free(mod->ctx, yin);
4717 } else {
4718 /* may try again later, put all back how it was */
4719 stype->der = (struct lys_tpdf *)yin;
4720 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004721 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004722 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004723 case UNRES_IFFEAT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004724 node = str_snode;
4725 expr = item;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004726
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004727 rc = resolve_iffeature_expr(expr, strlen(expr), node);
4728 if (rc == 2) {
4729 rc = EXIT_FAILURE;
4730 } else if (rc == 1) {
4731 rc = EXIT_SUCCESS;
4732 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004733 break;
4734 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004735 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004736 break;
4737 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004738 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004739 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004740 stype = item;
4741
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004742 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004743 break;
4744 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004745 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004746 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004747 choic = item;
4748
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004749 choic->dflt = resolve_choice_dflt(choic, expr);
Michal Vasko7955b362015-09-04 14:18:15 +02004750 if (choic->dflt) {
4751 rc = EXIT_SUCCESS;
4752 } else {
4753 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004754 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004755 break;
4756 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004757 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004758 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004759 break;
4760 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004761 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004762 rc = resolve_unique(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004763 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004764 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004765 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01004766 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004767 default:
4768 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004769 break;
4770 }
4771
Radek Krejci054d5ac2016-06-07 10:24:03 +02004772 if (has_str && (!rc || rc != EXIT_FAILURE)) {
4773 /* the string is no more needed in case of success
4774 * or fatal error. In case of forward reference,
4775 * we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01004776 lydict_remove(mod->ctx, str_snode);
4777 }
4778
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004779 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004780}
4781
Michal Vaskof02e3742015-08-05 16:27:02 +02004782/* logs directly */
4783static void
Radek Krejci48464ed2016-03-17 15:44:09 +01004784print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004785{
Michal Vaskocb34dc62016-05-20 14:38:37 +02004786 struct lyxml_elem *xml;
4787 struct lyxml_attr *attr;
Radek Krejci76e15e12016-06-22 11:02:24 +02004788 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02004789
Michal Vaskof02e3742015-08-05 16:27:02 +02004790 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004791 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004792 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004793 break;
4794 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004795 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004796 break;
4797 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004798 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
4799 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02004800 break;
4801 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02004802 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
4803 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
4804 type_name = ((struct yang_type *)xml)->name;
4805 } else {
4806 LY_TREE_FOR(xml->attr, attr) {
4807 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
4808 type_name = attr->value;
4809 break;
4810 }
4811 }
4812 assert(attr);
4813 }
4814 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004815 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004816 case UNRES_IFFEAT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02004817 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)item);
Michal Vaskof02e3742015-08-05 16:27:02 +02004818 break;
4819 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004820 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004821 break;
4822 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004823 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004824 break;
4825 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004826 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004827 break;
4828 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01004829 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004830 break;
4831 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01004832 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004833 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004834 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004835 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
4836 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01004837 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004838 default:
4839 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004840 break;
4841 }
4842}
4843
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004844/**
Michal Vaskobb211122015-08-19 14:03:11 +02004845 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004846 *
4847 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004848 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004849 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004850 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004851 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004852int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004853resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004854{
Radek Krejci010e54b2016-03-15 09:40:34 +01004855 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004856 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004857
4858 assert(unres);
4859
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02004860 LOGVRB("Resolving unresolved schema nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01004861 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02004862
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004863 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004864 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004865 unres_count = 0;
4866 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004867
4868 for (i = 0; i < unres->count; ++i) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02004869 /* we do not need to have UNRES_TYPE_IDENTREF resolved, we need its type's base only,
4870 * but UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers) */
4871 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)
4872 && (unres->type[i] != UNRES_TYPE_LEAFREF)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004873 continue;
4874 }
4875
Michal Vasko88c29542015-11-27 14:57:53 +01004876 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01004877 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004878 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004879 unres->type[i] = UNRES_RESOLVED;
4880 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004881 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004882 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004883 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02004884 /* print the error */
4885 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004886 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02004887 } else {
4888 /* forward reference, erase ly_errno */
4889 ly_errno = LY_SUCCESS;
4890 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02004891 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004892 }
Michal Vasko88c29542015-11-27 14:57:53 +01004893 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004894
Michal Vasko88c29542015-11-27 14:57:53 +01004895 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02004896 /* just print the errors */
4897 ly_vlog_hide(0);
4898
4899 for (i = 0; i < unres->count; ++i) {
4900 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)
4901 && (unres->type[i] != UNRES_TYPE_LEAFREF)) {
4902 continue;
4903 }
4904 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
4905 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004906 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004907 }
4908
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004909 /* the rest */
4910 for (i = 0; i < unres->count; ++i) {
4911 if (unres->type[i] == UNRES_RESOLVED) {
4912 continue;
4913 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004914
Radek Krejci48464ed2016-03-17 15:44:09 +01004915 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004916 if (rc == 0) {
4917 unres->type[i] = UNRES_RESOLVED;
4918 ++resolved;
4919 } else if (rc == -1) {
4920 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02004921 /* print the error */
4922 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
4923 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004924 }
4925 }
4926
Radek Krejci010e54b2016-03-15 09:40:34 +01004927 ly_vlog_hide(0);
4928
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004929 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004930 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
4931 * all the validation errors
4932 */
4933 for (i = 0; i < unres->count; ++i) {
4934 if (unres->type[i] == UNRES_RESOLVED) {
4935 continue;
4936 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004937 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004938 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004939 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004940 }
4941
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02004942 LOGVRB("All schema nodes and constraints resolved.");
Radek Krejcic071c542016-01-27 14:57:51 +01004943 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004944 return EXIT_SUCCESS;
4945}
4946
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004947/**
Michal Vaskobb211122015-08-19 14:03:11 +02004948 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004949 *
4950 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004951 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004952 * @param[in] item Item to resolve. Type determined by \p type.
4953 * @param[in] type Type of the unresolved item.
4954 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004955 *
4956 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4957 */
4958int
Radek Krejci48464ed2016-03-17 15:44:09 +01004959unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
4960 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004961{
Radek Krejci48464ed2016-03-17 15:44:09 +01004962 return unres_schema_add_node(mod, unres, item, type, (struct lys_node *)lydict_insert(mod->ctx, str, 0));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963}
4964
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004965/**
Michal Vaskobb211122015-08-19 14:03:11 +02004966 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004967 *
4968 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004969 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004970 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004971 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004972 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004973 *
4974 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4975 */
4976int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004977unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01004978 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004979{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004980 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004981 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01004982 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004983
Michal Vasko9bf425b2015-10-22 11:42:03 +02004984 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4985 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004986
Radek Krejci010e54b2016-03-15 09:40:34 +01004987 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004988 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004989 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004990 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004991 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02004992 if (ly_log_level >= LY_LLERR) {
4993 path = strdup(ly_errpath());
4994 msg = strdup(ly_errmsg());
4995 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
4996 free(path);
4997 free(msg);
4998 }
Radek Krejci010e54b2016-03-15 09:40:34 +01004999 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005000 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02005001 } else {
5002 /* erase info about validation errors */
5003 ly_errno = LY_SUCCESS;
5004 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005005 }
5006
Radek Krejci48464ed2016-03-17 15:44:09 +01005007 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02005008
Michal Vasko88c29542015-11-27 14:57:53 +01005009 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
5010 if (type == UNRES_TYPE_DER) {
5011 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005012 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
5013 lyxml_unlink_elem(mod->ctx, yin, 1);
5014 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
5015 }
Michal Vasko88c29542015-11-27 14:57:53 +01005016 }
5017
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005018 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01005019 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
5020 if (!unres->item) {
5021 LOGMEM;
5022 return -1;
5023 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005024 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01005025 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
5026 if (!unres->type) {
5027 LOGMEM;
5028 return -1;
5029 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005030 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01005031 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
5032 if (!unres->str_snode) {
5033 LOGMEM;
5034 return -1;
5035 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005036 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01005037 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
5038 if (!unres->module) {
5039 LOGMEM;
5040 return -1;
5041 }
5042 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005043
5044 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005045}
5046
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005047/**
Michal Vaskobb211122015-08-19 14:03:11 +02005048 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005049 *
5050 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005051 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005052 * @param[in] item Old item to be resolved.
5053 * @param[in] type Type of the old unresolved item.
5054 * @param[in] new_item New item to use in the duplicate.
5055 *
5056 * @return EXIT_SUCCESS on success, -1 on error.
5057 */
Michal Vaskodad19402015-08-06 09:51:53 +02005058int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005059unres_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 +02005060{
5061 int i;
5062
Michal Vaskocf024702015-10-08 15:01:42 +02005063 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005064
Michal Vasko0bd29d12015-08-19 11:45:49 +02005065 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005066
5067 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005068 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005069 }
5070
Michal Vasko0d204592015-10-07 09:50:04 +02005071 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005072 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005073 LOGINT;
5074 return -1;
5075 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005076 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01005077 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005078 LOGINT;
5079 return -1;
5080 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005081 }
Michal Vaskodad19402015-08-06 09:51:53 +02005082
5083 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005084}
5085
Michal Vaskof02e3742015-08-05 16:27:02 +02005086/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005087int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005088unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005089{
5090 uint32_t ret = -1, i;
5091
5092 for (i = 0; i < unres->count; ++i) {
5093 if ((unres->item[i] == item) && (unres->type[i] == type)) {
5094 ret = i;
5095 break;
5096 }
5097 }
5098
5099 return ret;
5100}
Michal Vasko8bcdf292015-08-19 14:04:43 +02005101
Michal Vaskoede9c472016-06-07 09:38:15 +02005102static void
5103unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
5104{
5105 struct lyxml_elem *yin;
5106 struct yang_type *yang;
5107
5108 switch (unres->type[i]) {
5109 case UNRES_TYPE_DER:
5110 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
5111 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5112 yang =(struct yang_type *)yin;
5113 yang->type->base = yang->base;
5114 lydict_remove(ctx, yang->name);
5115 free(yang);
5116 } else {
5117 lyxml_free(ctx, yin);
5118 }
5119 break;
5120 case UNRES_IDENT:
5121 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02005122 case UNRES_TYPE_DFLT:
5123 case UNRES_CHOICE_DFLT:
5124 case UNRES_LIST_KEYS:
5125 case UNRES_LIST_UNIQ:
5126 lydict_remove(ctx, (const char *)unres->str_snode[i]);
5127 break;
5128 default:
5129 break;
5130 }
5131 unres->type[i] = UNRES_RESOLVED;
5132}
5133
Michal Vasko88c29542015-11-27 14:57:53 +01005134void
Radek Krejcic071c542016-01-27 14:57:51 +01005135unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01005136{
5137 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01005138 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01005139
Radek Krejcic071c542016-01-27 14:57:51 +01005140 if (!unres || !(*unres)) {
5141 return;
Michal Vasko88c29542015-11-27 14:57:53 +01005142 }
5143
Radek Krejcic071c542016-01-27 14:57:51 +01005144 assert(module || (*unres)->count == 0);
5145
5146 for (i = 0; i < (*unres)->count; ++i) {
5147 if ((*unres)->module[i] != module) {
5148 if ((*unres)->type[i] != UNRES_RESOLVED) {
5149 unresolved++;
5150 }
5151 continue;
5152 }
Michal Vaskoede9c472016-06-07 09:38:15 +02005153
5154 /* free heap memory for the specific item */
5155 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01005156 }
5157
Michal Vaskoede9c472016-06-07 09:38:15 +02005158 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01005159 if (!module || (!unresolved && !module->type)) {
5160 free((*unres)->item);
5161 free((*unres)->type);
5162 free((*unres)->str_snode);
5163 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01005164 free((*unres));
5165 (*unres) = NULL;
5166 }
Michal Vasko88c29542015-11-27 14:57:53 +01005167}
5168
Michal Vasko8bcdf292015-08-19 14:04:43 +02005169/**
5170 * @brief Resolve a single unres data item. Logs directly.
5171 *
Michal Vaskocf024702015-10-08 15:01:42 +02005172 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02005173 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02005174 *
5175 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5176 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02005177int
Radek Krejci48464ed2016-03-17 15:44:09 +01005178resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02005179{
5180 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02005181 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02005182 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005183 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02005184 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005185 struct unres_data matches;
5186
5187 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02005188 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02005189 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005190
Michal Vaskocf024702015-10-08 15:01:42 +02005191 switch (type) {
5192 case UNRES_LEAFREF:
5193 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vasko2471e7f2016-04-11 11:00:15 +02005194 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
5195 if (resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches) == -1) {
5196 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005197 }
5198
5199 /* check that value matches */
5200 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01005201 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02005202 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02005203 break;
5204 }
5205 }
5206
Michal Vaskocf024702015-10-08 15:01:42 +02005207 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005208
Michal Vaskocf024702015-10-08 15:01:42 +02005209 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02005210 /* reference not found */
Michal Vasko6ac68282016-04-11 10:56:47 +02005211 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005212 return EXIT_FAILURE;
5213 }
Michal Vaskocf024702015-10-08 15:01:42 +02005214 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005215
Michal Vaskocf024702015-10-08 15:01:42 +02005216 case UNRES_INSTID:
Michal Vasko976a5f22016-05-18 13:28:42 +02005217 assert((sleaf->type.base == LY_TYPE_INST) || (sleaf->type.base == LY_TYPE_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02005218 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01005219 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01005220 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02005221 if (ly_errno) {
5222 return -1;
5223 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005224 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005225 return EXIT_FAILURE;
5226 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01005227 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005228 }
5229 }
Michal Vaskocf024702015-10-08 15:01:42 +02005230 break;
5231
5232 case UNRES_WHEN:
Radek Krejci48464ed2016-03-17 15:44:09 +01005233 if ((rc = resolve_when(node))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005234 return rc;
5235 }
5236 break;
5237
Michal Vaskobf19d252015-10-08 15:39:17 +02005238 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01005239 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005240 return rc;
5241 }
5242 break;
5243
Michal Vaskoc4280842016-04-19 16:10:42 +02005244 case UNRES_EMPTYCONT:
5245 do {
5246 parent = node->parent;
5247 lyd_free(node);
5248 node = parent;
5249 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
5250 && !((struct lys_node_container *)node->schema)->presence);
5251 break;
5252
Michal Vaskocf024702015-10-08 15:01:42 +02005253 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02005254 LOGINT;
5255 return -1;
5256 }
5257
5258 return EXIT_SUCCESS;
5259}
5260
5261/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01005262 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02005263 *
5264 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02005265 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02005266 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01005267 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02005268 */
5269int
Radek Krejci0b7704f2016-03-18 12:16:14 +01005270unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02005271{
Radek Krejci03b71f72016-03-16 11:10:09 +01005272 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02005273 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
5274 || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02005275
Radek Krejci03b71f72016-03-16 11:10:09 +01005276 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01005277 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
5278 if (!unres->node) {
5279 LOGMEM;
5280 return -1;
5281 }
Michal Vaskocf024702015-10-08 15:01:42 +02005282 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01005283 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
5284 if (!unres->type) {
5285 LOGMEM;
5286 return -1;
5287 }
Michal Vaskocf024702015-10-08 15:01:42 +02005288 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005289
Radek Krejci0b7704f2016-03-18 12:16:14 +01005290 if (type == UNRES_WHEN) {
5291 /* remove previous result */
5292 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005293 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005294
5295 return EXIT_SUCCESS;
5296}
5297
5298/**
5299 * @brief Resolve every unres data item in the structure. Logs directly.
5300 *
5301 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01005302 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
5303 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01005304 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005305 *
5306 * @return EXIT_SUCCESS on success, -1 on error.
5307 */
5308int
Radek Krejci0c0086a2016-03-24 15:20:28 +01005309resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005310{
Radek Krejci0c0086a2016-03-24 15:20:28 +01005311 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01005312 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01005313 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005314 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005315
Radek Krejci03b71f72016-03-16 11:10:09 +01005316 assert(unres);
Radek Krejci8ee1b562016-03-31 10:58:31 +02005317 assert((root && (*root)) || (options & LYD_OPT_NOAUTODEL));
Radek Krejci03b71f72016-03-16 11:10:09 +01005318
5319 if (!unres->count) {
5320 return EXIT_SUCCESS;
5321 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005322
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005323 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01005324 ly_vlog_hide(1);
5325
Radek Krejci0b7704f2016-03-18 12:16:14 +01005326 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01005327 ly_errno = LY_SUCCESS;
5328 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005329 do {
5330 progress = 0;
5331 for(i = 0; i < unres->count; i++) {
5332 if (unres->type[i] != UNRES_WHEN) {
5333 continue;
5334 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005335 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005336 /* count when-stmt nodes in unres list */
5337 when_stmt++;
5338 }
5339
5340 /* resolve when condition only when all parent when conditions are already resolved */
5341 for (parent = unres->node[i]->parent;
5342 parent && LYD_WHEN_DONE(parent->when_status);
5343 parent = parent->parent) {
5344 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
5345 /* the parent node was already unlinked, do not resolve this node,
5346 * it will be removed anyway, so just mark it as resolved
5347 */
5348 unres->node[i]->when_status |= LYD_WHEN_FALSE;
5349 unres->type[i] = UNRES_RESOLVED;
5350 resolved++;
5351 break;
5352 }
5353 }
5354 if (parent) {
5355 continue;
5356 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005357
Radek Krejci48464ed2016-03-17 15:44:09 +01005358 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005359 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005360 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
5361 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005362 /* false when condition */
5363 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02005364 if (ly_log_level >= LY_LLERR) {
5365 path = strdup(ly_errpath());
5366 msg = strdup(ly_errmsg());
5367 LOGERR(LY_EVALID, "%s%s%s%s", msg,
5368 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
5369 free(path);
5370 free(msg);
5371 }
Radek Krejci03b71f72016-03-16 11:10:09 +01005372 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005373 } /* follows else */
5374
Radek Krejci0c0086a2016-03-24 15:20:28 +01005375 /* only unlink now, the subtree can contain another nodes stored in the unres list */
5376 /* if it has parent non-presence containers that would be empty, we should actually
5377 * remove the container
5378 */
5379 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
5380 for (parent = unres->node[i];
5381 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
5382 parent = parent->parent) {
5383 if (((struct lys_node_container *)parent->parent->schema)->presence) {
5384 /* presence container */
5385 break;
5386 }
5387 if (parent->next || parent->prev != parent) {
5388 /* non empty (the child we are in and we are going to remove is not the only child) */
5389 break;
5390 }
5391 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005392 unres->node[i] = parent;
5393 }
5394
Radek Krejci0b7704f2016-03-18 12:16:14 +01005395 /* auto-delete */
5396 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
5397 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01005398 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005399 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01005400 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005401
Radek Krejci0b7704f2016-03-18 12:16:14 +01005402 lyd_unlink(unres->node[i]);
5403 unres->type[i] = UNRES_DELETE;
5404 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01005405
5406 /* update the rest of unres items */
5407 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01005408 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01005409 continue;
5410 }
5411
5412 /* test if the node is in subtree to be deleted */
5413 for (parent = unres->node[j]; parent; parent = parent->parent) {
5414 if (parent == unres->node[i]) {
5415 /* yes, it is */
5416 unres->type[j] = UNRES_RESOLVED;
5417 resolved++;
5418 break;
5419 }
5420 }
5421 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005422 } else {
5423 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01005424 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005425 ly_errno = LY_SUCCESS;
5426 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005427 resolved++;
5428 progress = 1;
5429 } else if (rc == -1) {
5430 ly_vlog_hide(0);
5431 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02005432 } else {
5433 /* forward reference, erase ly_errno */
5434 ly_errno = LY_SUCCESS;
5435 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005436 }
5437 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005438 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005439 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01005440
Radek Krejci0b7704f2016-03-18 12:16:14 +01005441 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01005442 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005443 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02005444 if (ly_log_level >= LY_LLERR) {
5445 path = strdup(ly_errpath());
5446 msg = strdup(ly_errmsg());
5447 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
5448 free(path);
5449 free(msg);
5450 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005451 return -1;
5452 }
5453
5454 for (i = 0; del_items && i < unres->count; i++) {
5455 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
5456 if (unres->type[i] != UNRES_DELETE) {
5457 continue;
5458 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005459 if (!unres->node[i]) {
5460 unres->type[i] = UNRES_RESOLVED;
5461 del_items--;
5462 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005463 }
5464
5465 /* really remove the complete subtree */
5466 lyd_free(unres->node[i]);
5467 unres->type[i] = UNRES_RESOLVED;
5468 del_items--;
5469 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005470
5471 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005472 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005473 if (unres->type[i] == UNRES_RESOLVED) {
5474 continue;
5475 }
5476
Radek Krejci48464ed2016-03-17 15:44:09 +01005477 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005478 if (rc == 0) {
5479 unres->type[i] = UNRES_RESOLVED;
5480 resolved++;
5481 } else if (rc == -1) {
5482 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02005483 /* print only this last error */
5484 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005485 return -1;
5486 }
5487 }
5488
Radek Krejci010e54b2016-03-15 09:40:34 +01005489 ly_vlog_hide(0);
5490 if (resolved < unres->count) {
5491 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
5492 * all the validation errors
5493 */
5494 for (i = 0; i < unres->count; ++i) {
5495 if (unres->type[i] == UNRES_RESOLVED) {
5496 continue;
5497 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005498 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005499 }
5500 return -1;
5501 }
5502
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005503 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01005504 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005505 return EXIT_SUCCESS;
5506}