blob: f3d77074c79e80abc5058a0ae5d0764f07fd0f86 [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) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200558 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200559 } else if (model && !*model) {
560 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200561 }
562
563 parsed += ret;
564 id += ret;
565
566 if ((id[0] == '[') && has_predicate) {
567 *has_predicate = 1;
568 }
569
570 return parsed;
571}
572
573/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200574 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200575 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200576 *
577 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
578 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
579 * ((DQUOTE string DQUOTE) /
580 * (SQUOTE string SQUOTE))
581 * pos = non-negative-integer-value
582 *
Michal Vaskobb211122015-08-19 14:03:11 +0200583 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200584 * @param[out] model Points to the model name.
585 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200586 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
587 * @param[out] nam_len Length of the node name.
588 * @param[out] value Value the node-identifier must have (string from the grammar),
589 * NULL if there is not any.
590 * @param[out] val_len Length of the value, 0 if there is not any.
591 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
592 *
593 * @return Number of characters successfully parsed,
594 * positive on success, negative on failure.
595 */
596static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200597parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
598 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200599{
600 const char *ptr;
601 int parsed = 0, ret;
602 char quote;
603
604 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200605 if (model) {
606 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200607 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200608 if (mod_len) {
609 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200610 }
611 if (name) {
612 *name = NULL;
613 }
614 if (nam_len) {
615 *nam_len = 0;
616 }
617 if (value) {
618 *value = NULL;
619 }
620 if (val_len) {
621 *val_len = 0;
622 }
623 if (has_predicate) {
624 *has_predicate = 0;
625 }
626
627 if (id[0] != '[') {
628 return -parsed;
629 }
630
631 ++parsed;
632 ++id;
633
634 while (isspace(id[0])) {
635 ++parsed;
636 ++id;
637 }
638
639 /* pos */
640 if (isdigit(id[0])) {
641 if (name) {
642 *name = id;
643 }
644
645 if (id[0] == '0') {
646 ++parsed;
647 ++id;
648
649 if (isdigit(id[0])) {
650 return -parsed;
651 }
652 }
653
654 while (isdigit(id[0])) {
655 ++parsed;
656 ++id;
657 }
658
659 if (nam_len) {
660 *nam_len = id-(*name);
661 }
662
663 /* "." */
664 } else if (id[0] == '.') {
665 if (name) {
666 *name = id;
667 }
668 if (nam_len) {
669 *nam_len = 1;
670 }
671
672 ++parsed;
673 ++id;
674
675 /* node-identifier */
676 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200677 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200679 } else if (model && !*model) {
680 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200681 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682
683 parsed += ret;
684 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200685 }
686
687 while (isspace(id[0])) {
688 ++parsed;
689 ++id;
690 }
691
692 if (id[0] != '=') {
693 return -parsed;
694 }
695
696 ++parsed;
697 ++id;
698
699 while (isspace(id[0])) {
700 ++parsed;
701 ++id;
702 }
703
704 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
705 if ((id[0] == '\"') || (id[0] == '\'')) {
706 quote = id[0];
707
708 ++parsed;
709 ++id;
710
711 if ((ptr = strchr(id, quote)) == NULL) {
712 return -parsed;
713 }
714 ret = ptr-id;
715
716 if (value) {
717 *value = id;
718 }
719 if (val_len) {
720 *val_len = ret;
721 }
722
723 parsed += ret+1;
724 id += ret+1;
725 } else {
726 return -parsed;
727 }
728
729 while (isspace(id[0])) {
730 ++parsed;
731 ++id;
732 }
733
734 if (id[0] != ']') {
735 return -parsed;
736 }
737
738 ++parsed;
739 ++id;
740
741 if ((id[0] == '[') && has_predicate) {
742 *has_predicate = 1;
743 }
744
745 return parsed;
746}
747
748/**
749 * @brief Parse schema-nodeid.
750 *
751 * schema-nodeid = absolute-schema-nodeid /
752 * descendant-schema-nodeid
753 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200754 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200755 * node-identifier
756 * absolute-schema-nodeid
757 *
Michal Vaskobb211122015-08-19 14:03:11 +0200758 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200759 * @param[out] mod_name Points to the module name, NULL if there is not any.
760 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200761 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200762 * @param[out] nam_len Length of the node name.
763 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
764 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100765 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
766 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200767 *
768 * @return Number of characters successfully parsed,
769 * positive on success, negative on failure.
770 */
Michal Vasko22448d32016-03-16 13:17:29 +0100771int
Michal Vasko723e50c2015-10-20 15:20:29 +0200772parse_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 +0100773 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200774{
775 int parsed = 0, ret;
776
777 assert(id);
778 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200779 if (mod_name) {
780 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200781 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200782 if (mod_name_len) {
783 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200784 }
785 if (name) {
786 *name = NULL;
787 }
788 if (nam_len) {
789 *nam_len = 0;
790 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100791 if (has_predicate) {
792 *has_predicate = 0;
793 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200794
795 if (id[0] != '/') {
796 if (*is_relative != -1) {
797 return -parsed;
798 } else {
799 *is_relative = 1;
800 }
Michal Vasko48935352016-03-29 11:52:36 +0200801 if (!strncmp(id, "./", 2)) {
802 parsed += 2;
803 id += 2;
804 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200805 } else {
806 if (*is_relative == -1) {
807 *is_relative = 0;
808 }
809 ++parsed;
810 ++id;
811 }
812
Michal Vasko723e50c2015-10-20 15:20:29 +0200813 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200814 return -parsed+ret;
815 }
816
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100817 parsed += ret;
818 id += ret;
819
820 if ((id[0] == '[') && has_predicate) {
821 *has_predicate = 1;
822 }
823
824 return parsed;
825}
826
827/**
828 * @brief Parse schema predicate (special format internally used).
829 *
830 * predicate = "[" *WSP predicate-expr *WSP "]"
831 * predicate-expr = identifier / key-with-value
832 * key-with-value = identifier *WSP "=" *WSP
833 * ((DQUOTE string DQUOTE) /
834 * (SQUOTE string SQUOTE))
835 *
836 * @param[in] id Identifier to use.
837 * @param[out] name Points to the list key name.
838 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100839 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100840 * @param[out] val_len Length of \p value.
841 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
842 */
Michal Vasko22448d32016-03-16 13:17:29 +0100843int
Michal Vasko3547c532016-03-14 09:40:50 +0100844parse_schema_list_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
845 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100846{
847 const char *ptr;
848 int parsed = 0, ret;
849 char quote;
850
851 assert(id);
852 if (name) {
853 *name = NULL;
854 }
855 if (nam_len) {
856 *nam_len = 0;
857 }
858 if (value) {
859 *value = NULL;
860 }
861 if (val_len) {
862 *val_len = 0;
863 }
864 if (has_predicate) {
865 *has_predicate = 0;
866 }
867
868 if (id[0] != '[') {
869 return -parsed;
870 }
871
872 ++parsed;
873 ++id;
874
875 while (isspace(id[0])) {
876 ++parsed;
877 ++id;
878 }
879
Michal Vasko22448d32016-03-16 13:17:29 +0100880 /* identifier */
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100881 if ((ret = parse_identifier(id)) < 1) {
882 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 Vasko3edeaf72016-02-11 13:17:43 +0100958 * @brief Resolve (find) a data node based on a schema-nodeid.
959 *
960 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
961 * module).
962 *
963 */
964struct lyd_node *
965resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
966{
967 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +0200968 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100969 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +0200970 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +0100971
972 assert(nodeid && start);
973
974 if (nodeid[0] == '/') {
975 return NULL;
976 }
977
978 str = p = strdup(nodeid);
979 if (!str) {
980 LOGMEM;
981 return NULL;
982 }
Radek Krejci5da4eb62016-04-08 14:45:51 +0200983
Michal Vasko3edeaf72016-02-11 13:17:43 +0100984 while (p) {
985 token = p;
986 p = strchr(p, '/');
987 if (p) {
988 *p = '\0';
989 p++;
990 }
991
Radek Krejci5da4eb62016-04-08 14:45:51 +0200992 if (p) {
993 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +0200994 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
995 LYS_CONTAINER | LYS_LIST | LYS_CHOICE | LYS_CASE | LYS_LEAF, &schema, 0)
Radek Krejci5da4eb62016-04-08 14:45:51 +0200996 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +0200997 result = NULL;
998 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +0200999 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001000
Radek Krejci5da4eb62016-04-08 14:45:51 +02001001 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1002 continue;
Radek Krejcicc217a62016-04-08 16:58:11 +02001003 } else if (schema->parent->nodetype == LYS_CHOICE) {
1004 /* shorthand case */
1005 if (!shorthand) {
1006 shorthand = 1;
1007 schema = schema->parent;
1008 continue;
1009 } else {
1010 shorthand = 0;
1011 if (schema->nodetype == LYS_LEAF) {
1012 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1013 result = NULL;
1014 break;
1015 }
1016 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001017 }
1018 } else {
1019 /* final node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001020 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, &schema, shorthand ? 0 : 1)
1021 || !schema) {
1022 result = NULL;
1023 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001024 }
1025 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001026 LY_TREE_FOR(result ? result->child : start, iter) {
1027 if (iter->schema == schema) {
1028 /* move in data tree according to returned schema */
1029 result = iter;
1030 break;
1031 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001032 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001033 if (!iter) {
1034 /* instance not found */
1035 result = NULL;
1036 break;
1037 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001038 }
1039 free(str);
1040
1041 return result;
1042}
1043
Radek Krejcibdf92362016-04-08 14:43:34 +02001044/*
1045 * 0 - ok (done)
1046 * 1 - continue
1047 * 2 - break
1048 * -1 - error
1049 */
1050static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001051schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001052 const struct lys_module *module, const char *mod_name, int mod_name_len,
1053 const struct lys_node **start)
1054{
1055 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001056 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001057
1058 /* module check */
1059 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1060 if (!prefix_mod) {
1061 return -1;
1062 }
1063 if (prefix_mod != lys_node_module(sibling)) {
1064 return 1;
1065 }
1066
1067 /* check for shorthand cases - then 'start' does not change */
1068 if (sibling->parent && sibling->parent->nodetype == LYS_CHOICE && sibling->nodetype != LYS_CASE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001069 if (*shorthand != -1) {
1070 *shorthand = *shorthand ? 0 : 1;
1071 }
1072 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001073 }
1074
1075 /* the result node? */
1076 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001077 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001078 return 1;
1079 }
1080 return 0;
1081 }
1082
Radek Krejcicc217a62016-04-08 16:58:11 +02001083 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001084 /* move down the tree, if possible */
1085 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1086 return -1;
1087 }
1088 *start = sibling->child;
1089 }
1090
1091 return 2;
1092}
1093
Michal Vasko3edeaf72016-02-11 13:17:43 +01001094/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1095int
1096resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1097 const struct lys_node **ret)
1098{
1099 const char *name, *mod_name, *id;
1100 const struct lys_node *sibling;
1101 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001102 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001103 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001104 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001105
1106 assert(nodeid && (start || module) && !(start && module) && ret);
1107
1108 id = nodeid;
1109
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001110 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 +01001111 return ((id - nodeid) - r) + 1;
1112 }
1113 id += r;
1114
1115 if ((is_relative && !start) || (!is_relative && !module)) {
1116 return -1;
1117 }
1118
1119 /* descendant-schema-nodeid */
1120 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001121 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001122
1123 /* absolute-schema-nodeid */
1124 } else {
1125 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001126 if (!start_mod) {
1127 return -1;
1128 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001129 start = start_mod->data;
1130 }
1131
1132 while (1) {
1133 sibling = NULL;
1134 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1135 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1136 /* name match */
1137 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
Michal Vasko044697a2016-03-24 13:21:12 +01001138 || ((sibling->nodetype == LYS_INPUT) && !strncmp(name, "input", nam_len) && (nam_len == 5))
1139 || ((sibling->nodetype == LYS_OUTPUT) && !strncmp(name, "output", nam_len) && (nam_len == 6))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001140
Radek Krejcibdf92362016-04-08 14:43:34 +02001141 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1142 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001143 *ret = sibling;
1144 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001145 } else if (r == 1) {
1146 continue;
1147 } else if (r == 2) {
1148 break;
1149 } else {
1150 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001151 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001152 }
1153 }
1154
1155 /* no match */
1156 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001157 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001158 return EXIT_SUCCESS;
1159 }
1160
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001161 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 +01001162 return ((id - nodeid) - r) + 1;
1163 }
1164 id += r;
1165 }
1166
1167 /* cannot get here */
1168 LOGINT;
1169 return -1;
1170}
1171
1172/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1173int
1174resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcicc217a62016-04-08 16:58:11 +02001175 const struct lys_node **ret, int check_shorthand)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001176{
1177 const char *name, *mod_name, *id;
1178 const struct lys_node *sibling;
1179 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001180 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001181 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001182 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001183
1184 assert(nodeid && start && ret);
1185 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1186
1187 id = nodeid;
1188 module = start->module;
1189
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001190 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 +01001191 return ((id - nodeid) - r) + 1;
1192 }
1193 id += r;
1194
1195 if (!is_relative) {
1196 return -1;
1197 }
1198
1199 while (1) {
1200 sibling = NULL;
1201 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1202 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1203 /* name match */
1204 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1205
Radek Krejcibdf92362016-04-08 14:43:34 +02001206 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1207 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001208 if (!(sibling->nodetype & ret_nodetype)) {
1209 /* wrong node type, too bad */
1210 continue;
1211 }
1212 *ret = sibling;
1213 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001214 } else if (r == 1) {
1215 continue;
1216 } else if (r == 2) {
1217 break;
1218 } else {
1219 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001220 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001221 }
1222 }
1223
1224 /* no match */
1225 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001226 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001227 return EXIT_SUCCESS;
1228 }
1229
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001230 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 +01001231 return ((id - nodeid) - r) + 1;
1232 }
1233 id += r;
1234 }
1235
1236 /* cannot get here */
1237 LOGINT;
1238 return -1;
1239}
1240
1241/* choice default */
1242int
1243resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1244{
1245 /* cannot actually be a path */
1246 if (strchr(nodeid, '/')) {
1247 return -1;
1248 }
1249
Radek Krejcicc217a62016-04-08 16:58:11 +02001250 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret, 1);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001251}
1252
1253/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1254static int
1255resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1256{
1257 const struct lys_module *module;
1258 const char *mod_prefix, *name;
1259 int i, mod_prefix_len, nam_len;
1260
1261 /* parse the identifier, it must be parsed on one call */
1262 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1263 return -i + 1;
1264 }
1265
1266 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1267 if (!module) {
1268 return -1;
1269 }
1270 if (module != start->module) {
1271 start = module->data;
1272 }
1273
1274 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1275
1276 return EXIT_SUCCESS;
1277}
1278
1279int
1280resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1281 const struct lys_node **ret)
1282{
1283 const char *name, *mod_name, *id;
1284 const struct lys_node *sibling, *start;
1285 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001286 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001287 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001288
1289 assert(nodeid && module && ret);
1290 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1291
1292 id = nodeid;
1293 start = module->data;
1294
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001295 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 +01001296 return ((id - nodeid) - r) + 1;
1297 }
1298 id += r;
1299
1300 if (is_relative) {
1301 return -1;
1302 }
1303
1304 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001305 if (!abs_start_mod) {
1306 return -1;
1307 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001308
1309 while (1) {
1310 sibling = NULL;
1311 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1312 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1313 /* name match */
Michal Vasko044697a2016-03-24 13:21:12 +01001314 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1315 || ((sibling->nodetype == LYS_INPUT) && !strncmp(name, "input", nam_len) && (nam_len == 5))
1316 || ((sibling->nodetype == LYS_OUTPUT) && !strncmp(name, "output", nam_len) && (nam_len == 6))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001317
Radek Krejcibdf92362016-04-08 14:43:34 +02001318 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1319 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001320 if (!(sibling->nodetype & ret_nodetype)) {
1321 /* wrong node type, too bad */
1322 continue;
1323 }
1324 *ret = sibling;
1325 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001326 } else if (r == 1) {
1327 continue;
1328 } else if (r == 2) {
1329 break;
1330 } else {
1331 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001332 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001333 }
1334 }
1335
1336 /* no match */
1337 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001338 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001339 return EXIT_SUCCESS;
1340 }
1341
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001342 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 +01001343 return ((id - nodeid) - r) + 1;
1344 }
1345 id += r;
1346 }
1347
1348 /* cannot get here */
1349 LOGINT;
1350 return -1;
1351}
1352
Michal Vaskoe733d682016-03-14 09:08:27 +01001353static int
Michal Vasko3547c532016-03-14 09:40:50 +01001354resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001355{
1356 const char *name;
1357 int nam_len, has_predicate, i;
1358
Michal Vasko3547c532016-03-14 09:40:50 +01001359 if ((i = parse_schema_list_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001360 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001361 return -1;
1362 }
1363
1364 predicate += i;
1365 *parsed += i;
1366
1367 for (i = 0; i < list->keys_size; ++i) {
1368 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1369 break;
1370 }
1371 }
1372
1373 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001374 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001375 return -1;
1376 }
1377
1378 /* more predicates? */
1379 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001380 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001381 }
1382
1383 return 0;
1384}
1385
Michal Vasko9fd98e22016-04-07 15:44:19 +02001386/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly
1387 * data_nodeid - 0 schema nodeid, 1 - data nodeid with RPC input, 2 - data nodeid with RPC output */
Michal Vaskoe733d682016-03-14 09:08:27 +01001388const struct lys_node *
Michal Vasko9fd98e22016-04-07 15:44:19 +02001389resolve_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 +01001390{
Michal Vasko10728b52016-04-07 14:26:29 +02001391 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001392 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001393 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001394 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001395 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001396 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001397
Michal Vasko3547c532016-03-14 09:40:50 +01001398 assert(nodeid && (ctx || start));
1399 if (!ctx) {
1400 ctx = start->module->ctx;
1401 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001402
1403 id = nodeid;
1404
Michal Vaskoe733d682016-03-14 09:08:27 +01001405 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 +01001406 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001407 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001408 }
1409 id += r;
1410
1411 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001412 assert(start);
1413 start = start->child;
1414 if (!start) {
1415 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001416 str = strndup(nodeid, (name + nam_len) - nodeid);
1417 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1418 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001419 return NULL;
1420 }
1421 module = start->module;
1422 } else {
1423 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001424 str = strndup(nodeid, (name + nam_len) - nodeid);
1425 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1426 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001427 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001428 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1429 LOGINT;
1430 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001431 }
1432
Michal Vasko971a3ca2016-04-01 13:09:29 +02001433 if (ly_buf_used && module_name[0]) {
1434 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1435 }
1436 ly_buf_used++;
1437
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001438 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001439 module_name[mod_name_len] = '\0';
1440 module = ly_ctx_get_module(ctx, module_name, NULL);
1441
1442 if (buf_backup) {
1443 /* return previous internal buffer content */
1444 strcpy(module_name, buf_backup);
1445 free(buf_backup);
1446 buf_backup = NULL;
1447 }
1448 ly_buf_used--;
1449
Michal Vasko3547c532016-03-14 09:40:50 +01001450 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001451 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1452 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1453 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001454 return NULL;
1455 }
1456 start = module->data;
1457
1458 /* now it's as if there was no module name */
1459 mod_name = NULL;
1460 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001461 }
1462
Michal Vaskoe733d682016-03-14 09:08:27 +01001463 prev_mod = module;
1464
Michal Vasko3edeaf72016-02-11 13:17:43 +01001465 while (1) {
1466 sibling = NULL;
Michal Vasko9fd98e22016-04-07 15:44:19 +02001467 while ((sibling = lys_getnext(sibling, lys_parent(start), module, (data_nodeid ?
1468 0 : LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT)))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001469 /* name match */
Michal Vasko044697a2016-03-24 13:21:12 +01001470 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1471 || ((sibling->nodetype == LYS_INPUT) && !strncmp(name, "input", nam_len) && (nam_len == 5))
1472 || ((sibling->nodetype == LYS_OUTPUT) && !strncmp(name, "output", nam_len) && (nam_len == 6))) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001473
1474 /* data RPC input/output check */
1475 if ((data_nodeid == 1) && sibling->parent && (sibling->parent->nodetype == LYS_OUTPUT)) {
1476 continue;
1477 } else if ((data_nodeid == 2) && sibling->parent && (sibling->parent->nodetype == LYS_INPUT)) {
1478 continue;
1479 }
1480
Michal Vasko3edeaf72016-02-11 13:17:43 +01001481 /* module check */
1482 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001483 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01001484 LOGINT;
1485 return NULL;
1486 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001487
1488 if (ly_buf_used && module_name[0]) {
1489 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1490 }
1491 ly_buf_used++;
1492
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001493 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01001494 module_name[mod_name_len] = '\0';
1495 /* will also find an augment module */
1496 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001497
1498 if (buf_backup) {
1499 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001500 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001501 free(buf_backup);
1502 buf_backup = NULL;
1503 }
1504 ly_buf_used--;
1505
Michal Vasko3edeaf72016-02-11 13:17:43 +01001506 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001507 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1508 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1509 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001510 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001511 }
1512 } else {
1513 prefix_mod = prev_mod;
1514 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001515 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001516 continue;
1517 }
1518
Michal Vaskoe733d682016-03-14 09:08:27 +01001519 /* do we have some predicates on it? */
1520 if (has_predicate) {
1521 r = 0;
1522 if (sibling->nodetype != LYS_LIST) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001523 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001524 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001525 } else if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001526 return NULL;
1527 }
1528 id += r;
1529 }
1530
Radek Krejcibdf92362016-04-08 14:43:34 +02001531 /* check for shorthand cases - then 'start' does not change */
1532 if (sibling->parent && sibling->parent->nodetype == LYS_CHOICE && sibling->nodetype != LYS_CASE) {
1533 shorthand = ~shorthand;
1534 }
1535
Michal Vasko3edeaf72016-02-11 13:17:43 +01001536 /* the result node? */
1537 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001538 if (shorthand) {
1539 /* wrong path for shorthand */
1540 sibling = NULL;
1541 break;
1542 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001543 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001544 }
1545
Radek Krejcibdf92362016-04-08 14:43:34 +02001546 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001547 /* move down the tree, if possible */
1548 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001549 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01001550 return NULL;
1551 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001552 start = sibling->child;
1553 }
1554
1555 /* update prev mod */
1556 prev_mod = start->module;
1557 break;
1558 }
1559 }
1560
1561 /* no match */
1562 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02001563 str = strndup(nodeid, (name + nam_len) - nodeid);
1564 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1565 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001566 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001567 }
1568
Michal Vaskoe733d682016-03-14 09:08:27 +01001569 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 +01001570 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001571 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001572 }
1573 id += r;
1574 }
1575
1576 /* cannot get here */
1577 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001578 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001579}
1580
Michal Vasko22448d32016-03-16 13:17:29 +01001581static int
1582resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
1583{
1584 const char *name, *value;
1585 int nam_len, val_len, has_predicate = 1, r;
1586 uint16_t i;
1587 struct ly_set *keys;
1588
Radek Krejci61a86c62016-03-24 11:06:44 +01001589 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01001590 assert(node->schema->nodetype == LYS_LIST);
1591
1592 keys = lyd_get_list_keys(node);
1593
1594 for (i = 0; i < keys->number; ++i) {
1595 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001596 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001597 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001598 }
1599
1600 if ((r = parse_schema_list_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001601 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Radek Krejciba5cec62016-03-24 10:40:29 +01001602 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001603 }
1604
1605 predicate += r;
1606 *parsed += r;
1607
Radek Krejci8f08df12016-03-21 11:11:30 +01001608 if (strncmp(keys->set.d[i]->schema->name, name, nam_len) || keys->set.d[i]->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001609 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001610 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001611 }
1612
1613 /* value does not match */
Radek Krejci8f08df12016-03-21 11:11:30 +01001614 if (strncmp(((struct lyd_node_leaf_list *)keys->set.d[i])->value_str, value, val_len)
1615 || ((struct lyd_node_leaf_list *)keys->set.d[i])->value_str[val_len]) {
Radek Krejciba5cec62016-03-24 10:40:29 +01001616 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001617 return 1;
1618 }
1619 }
1620
Radek Krejciba5cec62016-03-24 10:40:29 +01001621 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001622 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001623 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01001624 return -1;
1625 }
1626
1627 return 0;
Radek Krejciba5cec62016-03-24 10:40:29 +01001628
1629error:
1630 ly_set_free(keys);
1631 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001632}
1633
1634struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001635resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
1636 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01001637{
Michal Vasko10728b52016-04-07 14:26:29 +02001638 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01001639 const char *id, *mod_name, *name;
1640 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001641 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001642 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01001643 const struct lys_module *prefix_mod, *prev_mod;
1644 struct ly_ctx *ctx;
1645
1646 assert(nodeid && start && parsed);
1647
1648 ctx = start->schema->module->ctx;
1649 id = nodeid;
1650
1651 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 +01001652 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001653 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001654 return NULL;
1655 }
1656 id += r;
1657 /* add it to parsed only after the data node was actually found */
1658 last_parsed = r;
1659
1660 if (is_relative) {
1661 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01001662 start = start->child;
1663 } else {
1664 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01001665 prev_mod = start->schema->module;
1666 }
1667
1668 while (1) {
1669 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01001670 /* RPC data check, return simply invalid argument, because the data tree is invalid */
1671 if (lys_parent(sibling->schema)) {
1672 if (options & LYD_PATH_OPT_OUTPUT) {
1673 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vasko9ffd8992016-03-24 13:42:29 +01001674 LOGERR(LY_EINVAL, "%s: provided data tree includes some RPC input nodes.");
Michal Vasko2411b942016-03-23 13:50:03 +01001675 *parsed = -1;
1676 return NULL;
1677 }
1678 } else {
1679 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vasko9ffd8992016-03-24 13:42:29 +01001680 LOGERR(LY_EINVAL, "%s: provided data tree includes some RPC output nodes.");
Michal Vasko2411b942016-03-23 13:50:03 +01001681 *parsed = -1;
1682 return NULL;
1683 }
1684 }
1685 }
1686
Michal Vasko22448d32016-03-16 13:17:29 +01001687 /* name match */
1688 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
1689
1690 /* module check */
1691 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001692 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01001693 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001694 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001695 return NULL;
1696 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001697
1698 if (ly_buf_used && module_name[0]) {
1699 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1700 }
1701 ly_buf_used++;
1702
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001703 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01001704 module_name[mod_name_len] = '\0';
1705 /* will also find an augment module */
1706 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001707
1708 if (buf_backup) {
1709 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001710 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001711 free(buf_backup);
1712 buf_backup = NULL;
1713 }
1714 ly_buf_used--;
1715
Michal Vasko22448d32016-03-16 13:17:29 +01001716 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001717 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1718 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1719 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001720 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001721 return NULL;
1722 }
1723 } else {
1724 prefix_mod = prev_mod;
1725 }
1726 if (prefix_mod != lys_node_module(sibling->schema)) {
1727 continue;
1728 }
1729
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001730 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01001731 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001732 llist = (struct lyd_node_leaf_list *)sibling;
1733 if ((!llist_value && llist->value_str && llist->value_str[0])
1734 || (llist_value && strcmp(llist_value, llist->value_str))) {
1735 continue;
1736 }
Michal Vasko22448d32016-03-16 13:17:29 +01001737 }
1738
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001739 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01001740 if (sibling->schema->nodetype == LYS_LIST) {
1741 r = 0;
1742 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001743 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001744 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001745 return NULL;
1746 }
1747 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
1748 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01001749 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001750 return NULL;
1751 } else if (ret == 1) {
1752 /* this list instance does not match */
1753 continue;
1754 }
1755 id += r;
1756 last_parsed += r;
1757 }
1758
1759 *parsed += last_parsed;
1760
1761 /* the result node? */
1762 if (!id[0]) {
1763 return sibling;
1764 }
1765
1766 /* move down the tree, if possible */
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02001767 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001768 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001769 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001770 return NULL;
1771 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02001772 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01001773 start = sibling->child;
1774 if (start) {
1775 prev_mod = start->schema->module;
1776 }
1777 break;
1778 }
1779 }
1780
1781 /* no match, return last match */
1782 if (!sibling) {
1783 return last_match;
1784 }
1785
1786 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 +01001787 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001788 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001789 return NULL;
1790 }
1791 id += r;
1792 last_parsed = r;
1793 }
1794
1795 /* cannot get here */
1796 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001797 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001798 return NULL;
1799}
1800
Michal Vasko3edeaf72016-02-11 13:17:43 +01001801/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001802 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02001803 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001804 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02001805 * @param[in] str_restr Restriction as a string.
1806 * @param[in] type Type of the restriction.
1807 * @param[out] ret Final interval structure that starts with
1808 * the interval of the initial type, continues with intervals
1809 * of any superior types derived from the initial one, and
1810 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001811 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001812 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001813 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001814int
Michal Vaskoaeb51802016-04-11 10:58:47 +02001815resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001816{
1817 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02001818 int kind;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001819 int64_t local_smin, local_smax;
1820 uint64_t local_umin, local_umax;
1821 long double local_fmin, local_fmax;
1822 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02001823 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001824
1825 switch (type->base) {
1826 case LY_TYPE_BINARY:
1827 kind = 0;
1828 local_umin = 0;
1829 local_umax = 18446744073709551615UL;
1830
1831 if (!str_restr && type->info.binary.length) {
1832 str_restr = type->info.binary.length->expr;
1833 }
1834 break;
1835 case LY_TYPE_DEC64:
1836 kind = 2;
1837 local_fmin = -9223372036854775808.0;
1838 local_fmin /= 1 << type->info.dec64.dig;
1839 local_fmax = 9223372036854775807.0;
1840 local_fmax /= 1 << type->info.dec64.dig;
1841
1842 if (!str_restr && type->info.dec64.range) {
1843 str_restr = type->info.dec64.range->expr;
1844 }
1845 break;
1846 case LY_TYPE_INT8:
1847 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001848 local_smin = __INT64_C(-128);
1849 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001850
1851 if (!str_restr && type->info.num.range) {
1852 str_restr = type->info.num.range->expr;
1853 }
1854 break;
1855 case LY_TYPE_INT16:
1856 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001857 local_smin = __INT64_C(-32768);
1858 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001859
1860 if (!str_restr && type->info.num.range) {
1861 str_restr = type->info.num.range->expr;
1862 }
1863 break;
1864 case LY_TYPE_INT32:
1865 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001866 local_smin = __INT64_C(-2147483648);
1867 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001868
1869 if (!str_restr && type->info.num.range) {
1870 str_restr = type->info.num.range->expr;
1871 }
1872 break;
1873 case LY_TYPE_INT64:
1874 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001875 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1876 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001877
1878 if (!str_restr && type->info.num.range) {
1879 str_restr = type->info.num.range->expr;
1880 }
1881 break;
1882 case LY_TYPE_UINT8:
1883 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001884 local_umin = __UINT64_C(0);
1885 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001886
1887 if (!str_restr && type->info.num.range) {
1888 str_restr = type->info.num.range->expr;
1889 }
1890 break;
1891 case LY_TYPE_UINT16:
1892 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001893 local_umin = __UINT64_C(0);
1894 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001895
1896 if (!str_restr && type->info.num.range) {
1897 str_restr = type->info.num.range->expr;
1898 }
1899 break;
1900 case LY_TYPE_UINT32:
1901 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001902 local_umin = __UINT64_C(0);
1903 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001904
1905 if (!str_restr && type->info.num.range) {
1906 str_restr = type->info.num.range->expr;
1907 }
1908 break;
1909 case LY_TYPE_UINT64:
1910 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001911 local_umin = __UINT64_C(0);
1912 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001913
1914 if (!str_restr && type->info.num.range) {
1915 str_restr = type->info.num.range->expr;
1916 }
1917 break;
1918 case LY_TYPE_STRING:
1919 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001920 local_umin = __UINT64_C(0);
1921 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001922
1923 if (!str_restr && type->info.str.length) {
1924 str_restr = type->info.str.length->expr;
1925 }
1926 break;
1927 default:
1928 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001929 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001930 }
1931
1932 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02001933 if (type->der) {
1934 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001935 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001936 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001937 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001938 assert(!intv || (intv->kind == kind));
1939 }
1940
1941 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001942 /* we do not have any restriction, return superior ones */
1943 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001944 return EXIT_SUCCESS;
1945 }
1946
1947 /* adjust local min and max */
1948 if (intv) {
1949 tmp_intv = intv;
1950
1951 if (kind == 0) {
1952 local_umin = tmp_intv->value.uval.min;
1953 } else if (kind == 1) {
1954 local_smin = tmp_intv->value.sval.min;
1955 } else if (kind == 2) {
1956 local_fmin = tmp_intv->value.fval.min;
1957 }
1958
1959 while (tmp_intv->next) {
1960 tmp_intv = tmp_intv->next;
1961 }
1962
1963 if (kind == 0) {
1964 local_umax = tmp_intv->value.uval.max;
1965 } else if (kind == 1) {
1966 local_smax = tmp_intv->value.sval.max;
1967 } else if (kind == 2) {
1968 local_fmax = tmp_intv->value.fval.max;
1969 }
1970 }
1971
1972 /* finally parse our restriction */
1973 seg_ptr = str_restr;
1974 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001975 if (!tmp_local_intv) {
1976 assert(!local_intv);
1977 local_intv = malloc(sizeof *local_intv);
1978 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001979 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001980 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001981 tmp_local_intv = tmp_local_intv->next;
1982 }
Michal Vasko253035f2015-12-17 16:58:13 +01001983 if (!tmp_local_intv) {
1984 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02001985 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01001986 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001987
1988 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02001989 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001990 tmp_local_intv->next = NULL;
1991
1992 /* min */
1993 ptr = seg_ptr;
1994 while (isspace(ptr[0])) {
1995 ++ptr;
1996 }
1997 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1998 if (kind == 0) {
1999 tmp_local_intv->value.uval.min = atoll(ptr);
2000 } else if (kind == 1) {
2001 tmp_local_intv->value.sval.min = atoll(ptr);
2002 } else if (kind == 2) {
2003 tmp_local_intv->value.fval.min = atoll(ptr);
2004 }
2005
2006 if ((ptr[0] == '+') || (ptr[0] == '-')) {
2007 ++ptr;
2008 }
2009 while (isdigit(ptr[0])) {
2010 ++ptr;
2011 }
2012 } else if (!strncmp(ptr, "min", 3)) {
2013 if (kind == 0) {
2014 tmp_local_intv->value.uval.min = local_umin;
2015 } else if (kind == 1) {
2016 tmp_local_intv->value.sval.min = local_smin;
2017 } else if (kind == 2) {
2018 tmp_local_intv->value.fval.min = local_fmin;
2019 }
2020
2021 ptr += 3;
2022 } else if (!strncmp(ptr, "max", 3)) {
2023 if (kind == 0) {
2024 tmp_local_intv->value.uval.min = local_umax;
2025 } else if (kind == 1) {
2026 tmp_local_intv->value.sval.min = local_smax;
2027 } else if (kind == 2) {
2028 tmp_local_intv->value.fval.min = local_fmax;
2029 }
2030
2031 ptr += 3;
2032 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002033 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002034 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002035 }
2036
2037 while (isspace(ptr[0])) {
2038 ptr++;
2039 }
2040
2041 /* no interval or interval */
2042 if ((ptr[0] == '|') || !ptr[0]) {
2043 if (kind == 0) {
2044 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2045 } else if (kind == 1) {
2046 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2047 } else if (kind == 2) {
2048 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2049 }
2050 } else if (!strncmp(ptr, "..", 2)) {
2051 /* skip ".." */
2052 ptr += 2;
2053 while (isspace(ptr[0])) {
2054 ++ptr;
2055 }
2056
2057 /* max */
2058 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2059 if (kind == 0) {
2060 tmp_local_intv->value.uval.max = atoll(ptr);
2061 } else if (kind == 1) {
2062 tmp_local_intv->value.sval.max = atoll(ptr);
2063 } else if (kind == 2) {
2064 tmp_local_intv->value.fval.max = atoll(ptr);
2065 }
2066 } else if (!strncmp(ptr, "max", 3)) {
2067 if (kind == 0) {
2068 tmp_local_intv->value.uval.max = local_umax;
2069 } else if (kind == 1) {
2070 tmp_local_intv->value.sval.max = local_smax;
2071 } else if (kind == 2) {
2072 tmp_local_intv->value.fval.max = local_fmax;
2073 }
2074 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002075 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002076 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002077 }
2078 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002079 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002080 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002081 }
2082
2083 /* next segment (next OR) */
2084 seg_ptr = strchr(seg_ptr, '|');
2085 if (!seg_ptr) {
2086 break;
2087 }
2088 seg_ptr++;
2089 }
2090
2091 /* check local restrictions against superior ones */
2092 if (intv) {
2093 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002094 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002095
2096 while (tmp_local_intv && tmp_intv) {
2097 /* reuse local variables */
2098 if (kind == 0) {
2099 local_umin = tmp_local_intv->value.uval.min;
2100 local_umax = tmp_local_intv->value.uval.max;
2101
2102 /* it must be in this interval */
2103 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2104 /* this interval is covered, next one */
2105 if (local_umax <= tmp_intv->value.uval.max) {
2106 tmp_local_intv = tmp_local_intv->next;
2107 continue;
2108 /* ascending order of restrictions -> fail */
2109 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002110 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002111 }
2112 }
2113 } else if (kind == 1) {
2114 local_smin = tmp_local_intv->value.sval.min;
2115 local_smax = tmp_local_intv->value.sval.max;
2116
2117 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2118 if (local_smax <= tmp_intv->value.sval.max) {
2119 tmp_local_intv = tmp_local_intv->next;
2120 continue;
2121 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002122 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002123 }
2124 }
2125 } else if (kind == 2) {
2126 local_fmin = tmp_local_intv->value.fval.min;
2127 local_fmax = tmp_local_intv->value.fval.max;
2128
2129 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
2130 if (local_fmax <= tmp_intv->value.fval.max) {
2131 tmp_local_intv = tmp_local_intv->next;
2132 continue;
2133 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002134 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002135 }
2136 }
2137 }
2138
2139 tmp_intv = tmp_intv->next;
2140 }
2141
2142 /* some interval left uncovered -> fail */
2143 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002144 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002145 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002146 }
2147
Michal Vaskoaeb51802016-04-11 10:58:47 +02002148 /* append the local intervals to all the intervals of the superior types, return it all */
2149 if (intv) {
2150 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2151 tmp_intv->next = local_intv;
2152 } else {
2153 intv = local_intv;
2154 }
2155 *ret = intv;
2156
2157 return EXIT_SUCCESS;
2158
2159error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002160 while (intv) {
2161 tmp_intv = intv->next;
2162 free(intv);
2163 intv = tmp_intv;
2164 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002165 while (local_intv) {
2166 tmp_local_intv = local_intv->next;
2167 free(local_intv);
2168 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002169 }
2170
Michal Vaskoaeb51802016-04-11 10:58:47 +02002171 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002172}
2173
Michal Vasko730dfdf2015-08-11 14:48:05 +02002174/**
Michal Vasko88c29542015-11-27 14:57:53 +01002175 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002176 *
2177 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002178 * @param[in] mod_name Typedef name module name.
2179 * @param[in] module Main module.
2180 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002181 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002182 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002183 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002184 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002185int
Michal Vasko1e62a092015-12-01 12:27:20 +01002186resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2187 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002188{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002189 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002190 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002191 int tpdf_size;
2192
Michal Vasko1dca6882015-10-22 14:29:42 +02002193 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002194 /* no prefix, try built-in types */
2195 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2196 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002197 if (ret) {
2198 *ret = ly_types[i].def;
2199 }
2200 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002201 }
2202 }
2203 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002204 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002205 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002206 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002207 }
2208 }
2209
Michal Vasko1dca6882015-10-22 14:29:42 +02002210 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002211 /* search in local typedefs */
2212 while (parent) {
2213 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002214 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002215 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2216 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002217 break;
2218
Radek Krejci76512572015-08-04 09:47:08 +02002219 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002220 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2221 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002222 break;
2223
Radek Krejci76512572015-08-04 09:47:08 +02002224 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002225 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2226 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002227 break;
2228
Radek Krejci76512572015-08-04 09:47:08 +02002229 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02002230 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
2231 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002232 break;
2233
Radek Krejci76512572015-08-04 09:47:08 +02002234 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002235 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2236 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002237 break;
2238
Radek Krejci76512572015-08-04 09:47:08 +02002239 case LYS_INPUT:
2240 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02002241 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
2242 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002243 break;
2244
2245 default:
2246 parent = parent->parent;
2247 continue;
2248 }
2249
2250 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002251 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002252 if (ret) {
2253 *ret = &tpdf[i];
2254 }
2255 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002256 }
2257 }
2258
2259 parent = parent->parent;
2260 }
Radek Krejcic071c542016-01-27 14:57:51 +01002261 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002262 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002263 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002264 if (!module) {
2265 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002266 }
2267 }
2268
2269 /* search in top level typedefs */
2270 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002271 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002272 if (ret) {
2273 *ret = &module->tpdf[i];
2274 }
2275 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002276 }
2277 }
2278
2279 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002280 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002281 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002282 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002283 if (ret) {
2284 *ret = &module->inc[i].submodule->tpdf[j];
2285 }
2286 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002287 }
2288 }
2289 }
2290
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002291 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002292}
2293
Michal Vasko1dca6882015-10-22 14:29:42 +02002294/**
2295 * @brief Check the default \p value of the \p type. Logs directly.
2296 *
2297 * @param[in] type Type definition to use.
2298 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002299 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002300 *
2301 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2302 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002303static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002304check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002305{
Michal Vasko1dca6882015-10-22 14:29:42 +02002306 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002307 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002308
2309 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002310 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002311 node.value_str = value;
2312 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002313 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002314 if (!node.schema) {
2315 LOGMEM;
2316 return -1;
2317 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002318 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01002319 if (!node.schema->name) {
2320 LOGMEM;
2321 return -1;
2322 }
Michal Vasko56826402016-03-02 11:11:37 +01002323 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002324 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002325
Radek Krejci37b756f2016-01-18 10:15:03 +01002326 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002327 if (!type->info.lref.target) {
2328 ret = EXIT_FAILURE;
2329 goto finish;
2330 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002331 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002332
2333 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2334 /* it was converted to JSON format before, nothing else sensible we can do */
2335
2336 } else {
Radek Krejci0b7704f2016-03-18 12:16:14 +01002337 ret = lyp_parse_value(&node, NULL, 1);
Michal Vasko1dca6882015-10-22 14:29:42 +02002338 }
2339
2340finish:
2341 if (node.value_type == LY_TYPE_BITS) {
2342 free(node.value.bit);
2343 }
2344 free((char *)node.schema->name);
2345 free(node.schema);
2346
2347 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002348}
2349
Michal Vasko730dfdf2015-08-11 14:48:05 +02002350/**
2351 * @brief Check a key for mandatory attributes. Logs directly.
2352 *
2353 * @param[in] key The key to check.
2354 * @param[in] flags What flags to check.
2355 * @param[in] list The list of all the keys.
2356 * @param[in] index Index of the key in the key list.
2357 * @param[in] name The name of the keys.
2358 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002359 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002360 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002361 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002362static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002363check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002364{
Radek Krejciadb57612016-02-16 13:34:34 +01002365 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002366 char *dup = NULL;
2367 int j;
2368
2369 /* existence */
2370 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002371 if (name[len] != '\0') {
2372 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002373 if (!dup) {
2374 LOGMEM;
2375 return -1;
2376 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002377 dup[len] = '\0';
2378 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002379 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002380 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002381 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002382 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002383 }
2384
2385 /* uniqueness */
2386 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002387 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002388 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002389 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002390 }
2391 }
2392
2393 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002394 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002395 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002396 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002397 }
2398
2399 /* type of the leaf is not built-in empty */
2400 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002401 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002402 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002403 }
2404
2405 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002406 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002407 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002408 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002409 }
2410
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002411 /* key is not placed from augment */
2412 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002413 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
2414 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002415 return -1;
2416 }
2417
Michal Vaskocca47842016-03-17 10:31:07 +01002418 /* key is not when-conditional */
2419 if (key->when) {
Radek Krejci02a04992016-03-17 16:06:37 +01002420 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
2421 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
Radek Krejci581ce772015-11-10 17:22:40 +01002422 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002423 }
2424
Michal Vasko0b85aa82016-03-07 14:37:43 +01002425 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02002426}
Michal Vasko730dfdf2015-08-11 14:48:05 +02002427
2428/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002429 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002430 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002431 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002432 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002433 *
2434 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
2435 */
2436int
Radek Krejci48464ed2016-03-17 15:44:09 +01002437resolve_unique(struct lys_node *parent, const char *uniq_str_path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002438{
Radek Krejci581ce772015-11-10 17:22:40 +01002439 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002440 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002441
Radek Krejcicc217a62016-04-08 16:58:11 +02002442 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf, 1);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002443 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002444 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002445 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002446 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002447 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejci581ce772015-11-10 17:22:40 +01002448 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002449 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01002450 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01002451 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2452 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002453 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002454 }
Radek Krejci581ce772015-11-10 17:22:40 +01002455 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002457 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002458 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2459 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002460 rc = -1;
2461 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002462 }
2463
Radek Krejcicf509982015-12-15 09:22:44 +01002464 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01002465 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002466 return -1;
2467 }
2468
Radek Krejcica7efb72016-01-18 13:06:01 +01002469 /* set leaf's unique flag */
2470 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2471
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002472 return EXIT_SUCCESS;
2473
2474error:
2475
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002476 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002477}
2478
Michal Vasko730dfdf2015-08-11 14:48:05 +02002479/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002480 * @brief Resolve (find) a feature definition. Logs directly.
2481 *
2482 * @param[in] name Feature name.
2483 * @param[in] module Module to search in.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002484 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002485 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002486 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002487 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002488static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002489resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002490{
Michal Vasko2d851a92015-10-20 16:16:36 +02002491 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002492 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002493 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002494
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002495 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002496 assert(module);
2497
2498 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002499 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002500 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002501 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002502 }
2503
Radek Krejcic071c542016-01-27 14:57:51 +01002504 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2505 if (!module) {
2506 /* identity refers unknown data model */
Radek Krejci48464ed2016-03-17 15:44:09 +01002507 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002508 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002509 }
2510
Radek Krejcic071c542016-01-27 14:57:51 +01002511 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002512 for (j = 0; j < module->features_size; j++) {
2513 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002514 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002515 /* check status */
2516 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002517 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejci48464ed2016-03-17 15:44:09 +01002518 module->features[j].module, module->features[j].name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002519 return -1;
2520 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002521 *ret = &module->features[j];
2522 }
2523 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002524 }
2525 }
Radek Krejcic071c542016-01-27 14:57:51 +01002526 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002527 for (i = 0; i < module->inc_size; i++) {
2528 if (!module->inc[i].submodule) {
2529 /* not yet resolved */
2530 continue;
2531 }
Radek Krejcic071c542016-01-27 14:57:51 +01002532 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2533 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2534 if (ret) {
2535 /* check status */
2536 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002537 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002538 module->inc[i].submodule->features[j].flags,
2539 module->inc[i].submodule->features[j].module,
Radek Krejci48464ed2016-03-17 15:44:09 +01002540 module->inc[i].submodule->features[j].name, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002541 return -1;
2542 }
2543 *ret = &(module->inc[i].submodule->features[j]);
2544 }
2545 return EXIT_SUCCESS;
2546 }
2547 }
2548 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002549
2550 /* not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01002551 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002552 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002553}
2554
Radek Krejci0c0086a2016-03-24 15:20:28 +01002555void
Michal Vasko23b61ec2015-08-19 11:19:50 +02002556unres_data_del(struct unres_data *unres, uint32_t i)
2557{
2558 /* there are items after the one deleted */
2559 if (i+1 < unres->count) {
2560 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002561 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002562
2563 /* deleting the last item */
2564 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002565 free(unres->node);
2566 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002567 }
2568
2569 /* if there are no items after and it is not the last one, just move the counter */
2570 --unres->count;
2571}
2572
Michal Vasko0491ab32015-08-19 14:28:29 +02002573/**
2574 * @brief Resolve (find) a data node from a specific module. Does not log.
2575 *
2576 * @param[in] mod Module to search in.
2577 * @param[in] name Name of the data node.
2578 * @param[in] nam_len Length of the name.
2579 * @param[in] start Data node to start the search from.
2580 * @param[in,out] parents Resolved nodes. If there are some parents,
2581 * they are replaced (!!) with the resolvents.
2582 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02002583 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02002584 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002585static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002586resolve_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 +02002587{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002588 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002589 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002590 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002591
Michal Vasko23b61ec2015-08-19 11:19:50 +02002592 if (!parents->count) {
2593 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002594 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002595 if (!parents->node) {
2596 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02002597 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002598 }
Michal Vaskocf024702015-10-08 15:01:42 +02002599 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002600 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002601 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002602 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002603 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002604 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002605 continue;
2606 }
2607 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002608 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002609 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2610 && node->schema->name[nam_len] == '\0') {
2611 /* matching target */
2612 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002613 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002614 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002615 flag = 1;
2616 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002617 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002618 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002619 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2620 if (!parents->node) {
2621 return EXIT_FAILURE;
2622 }
Michal Vaskocf024702015-10-08 15:01:42 +02002623 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002624 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002625 }
2626 }
2627 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002628
2629 if (!flag) {
2630 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002631 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002632 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002633 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002635 }
2636
Michal Vasko0491ab32015-08-19 14:28:29 +02002637 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002638}
2639
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002640/**
2641 * @brief Resolve (find) a data node. Does not log.
2642 *
Radek Krejci581ce772015-11-10 17:22:40 +01002643 * @param[in] mod_name Module name of the data node.
2644 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002645 * @param[in] name Name of the data node.
2646 * @param[in] nam_len Length of the name.
2647 * @param[in] start Data node to start the search from.
2648 * @param[in,out] parents Resolved nodes. If there are some parents,
2649 * they are replaced (!!) with the resolvents.
2650 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002651 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002652 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002653static int
Radek Krejci581ce772015-11-10 17:22:40 +01002654resolve_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 +02002655 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002656{
Michal Vasko1e62a092015-12-01 12:27:20 +01002657 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002658 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002659
Michal Vasko23b61ec2015-08-19 11:19:50 +02002660 assert(start);
2661
Michal Vasko31fc3672015-10-21 12:08:13 +02002662 if (mod_name) {
2663 /* we have mod_name, find appropriate module */
2664 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002665 if (!str) {
2666 LOGMEM;
2667 return -1;
2668 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002669 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2670 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002671 if (!mod) {
2672 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002673 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002674 }
2675 } else {
2676 /* no prefix, module is the same as of current node */
2677 mod = start->schema->module;
2678 }
2679
2680 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002681}
2682
Michal Vasko730dfdf2015-08-11 14:48:05 +02002683/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002684 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01002685 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002686 *
Michal Vaskobb211122015-08-19 14:03:11 +02002687 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002688 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002689 * @param[in,out] node_match Nodes satisfying the restriction
2690 * without the predicate. Nodes not
2691 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002692 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002693 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002694 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002695 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002696static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002697resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01002698 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002699{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002700 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002701 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002702 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002703 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2704 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002705 uint32_t j;
2706
2707 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002708 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002709 if (!source_match.node) {
2710 LOGMEM;
2711 return -1;
2712 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002713 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002714 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002715 if (!dest_match.node) {
2716 LOGMEM;
2717 return -1;
2718 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002719
2720 do {
2721 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2722 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002723 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002724 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002725 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002726 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002727 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002728 pred += i;
2729
Michal Vasko23b61ec2015-08-19 11:19:50 +02002730 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002731 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002732 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002733
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002734 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002735 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002736 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002737 i = 0;
2738 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002739 }
2740
2741 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002742 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002743 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002744 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2745 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002746 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002747 rc = -1;
2748 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002749 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002750 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002751 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002752 dest_match.node[0] = dest_match.node[0]->parent;
2753 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002754 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002755 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002756 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002757 }
2758 }
2759 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002760 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002761 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002762 i = 0;
2763 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002764 }
2765
2766 if (pke_len == pke_parsed) {
2767 break;
2768 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002769 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 +02002770 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002771 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002772 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002773 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002774 }
2775 pke_parsed += i;
2776 }
2777
2778 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002779 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2780 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002781 goto remove_leafref;
2782 }
2783
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002784 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002785 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002786 goto remove_leafref;
2787 }
2788
2789 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002790 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002791 continue;
2792
2793remove_leafref:
2794 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002795 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796 }
2797 } while (has_predicate);
2798
Michal Vaskocf024702015-10-08 15:01:42 +02002799 free(source_match.node);
2800 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002801 if (parsed) {
2802 *parsed = parsed_loc;
2803 }
2804 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002805
2806error:
2807
2808 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002809 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002810 }
2811 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002812 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002813 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002814 if (parsed) {
2815 *parsed = -parsed_loc+i;
2816 }
2817 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002818}
2819
Michal Vasko730dfdf2015-08-11 14:48:05 +02002820/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002821 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002822 *
Michal Vaskocf024702015-10-08 15:01:42 +02002823 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002824 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01002825 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002826 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002827 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002828 */
Michal Vasko184521f2015-09-24 13:14:26 +02002829static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002830resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002831{
Radek Krejci71b795b2015-08-10 16:20:39 +02002832 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002833 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002834 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002835 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002836
Michal Vaskocf024702015-10-08 15:01:42 +02002837 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002838
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002839 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002840 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841
2842 /* searching for nodeset */
2843 do {
2844 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002845 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002846 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847 goto error;
2848 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002849 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002850 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002851
Michal Vasko23b61ec2015-08-19 11:19:50 +02002852 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002853 if (parent_times != -1) {
2854 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002855 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002856 if (!ret->node) {
2857 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002858 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002859 goto error;
2860 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002861 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 for (i = 0; i < parent_times; ++i) {
2863 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002864 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 /* error, too many .. */
Radek Krejci48464ed2016-03-17 15:44:09 +01002866 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002867 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002868 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002869 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002871 data = ret->node[0] = node->parent;
2872 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002873 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002874 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002875 free(ret->node);
2876 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 } else {
2878 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002879 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 }
2881 }
2882
2883 /* absolute path */
2884 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002885 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002886 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002887 if (data->prev) {
2888 for (; data->prev->next; data = data->prev);
2889 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002890 }
2891 }
2892
2893 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002894 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002895 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002896 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002897 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 goto error;
2899 }
2900
2901 if (has_predicate) {
2902 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002903 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002904 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2905 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002907 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002908 continue;
2909 }
2910
2911 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002912 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002913 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002914 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002915 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002916 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002917 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002918 goto error;
2919 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002920 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002921 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002922
Michal Vasko23b61ec2015-08-19 11:19:50 +02002923 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02002924 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002925 goto error;
2926 }
2927 }
2928 } while (path[0] != '\0');
2929
Michal Vaskof02e3742015-08-05 16:27:02 +02002930 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931
2932error:
2933
Michal Vaskocf024702015-10-08 15:01:42 +02002934 free(ret->node);
2935 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002936 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937
Michal Vasko0491ab32015-08-19 14:28:29 +02002938 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002939}
2940
Michal Vasko730dfdf2015-08-11 14:48:05 +02002941/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002942 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002943 *
Michal Vaskobb211122015-08-19 14:03:11 +02002944 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002945 * @param[in] context_node Predicate context node (where the predicate is placed).
2946 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02002947 *
Michal Vasko184521f2015-09-24 13:14:26 +02002948 * @return 0 on forward reference, otherwise the number
2949 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002950 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002951 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002952static int
Radek Krejciadb57612016-02-16 13:34:34 +01002953resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01002954 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02002955{
Michal Vasko1e62a092015-12-01 12:27:20 +01002956 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002957 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2958 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 +02002959 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002960
2961 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002962 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002963 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002964 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002965 return -parsed+i;
2966 }
2967 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002968 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002969
Michal Vasko58090902015-08-13 14:04:15 +02002970 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002971 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002972 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002973 }
Radek Krejciadb57612016-02-16 13:34:34 +01002974 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002975 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002976 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002977 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002978 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002979 }
2980 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002981 }
2982
2983 /* destination */
2984 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2985 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002986 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 +02002987 return -parsed;
2988 }
2989 pke_parsed += i;
2990
Radek Krejciadb57612016-02-16 13:34:34 +01002991 /* parent is actually the parent of this leaf, so skip the first ".." */
2992 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002993 if (!dst_node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002994 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002995 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002996 }
Radek Krejciadb57612016-02-16 13:34:34 +01002997 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002998 }
2999 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003000 if (!dest_pref) {
3001 dest_pref = dst_node->module->name;
3002 }
3003 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003004 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003005 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003006 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003007 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003008 }
3009 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003010 }
3011
3012 if (pke_len == pke_parsed) {
3013 break;
3014 }
3015
3016 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3017 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003018 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003019 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003020 return -parsed;
3021 }
3022 pke_parsed += i;
3023 }
3024
3025 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02003026 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003027 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
3028 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
3029 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003030 return -parsed;
3031 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003032 } while (has_predicate);
3033
3034 return parsed;
3035}
3036
Michal Vasko730dfdf2015-08-11 14:48:05 +02003037/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003038 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003039 *
Michal Vaskobb211122015-08-19 14:03:11 +02003040 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003041 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003042 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3043 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003044 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003045 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003046 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003047 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003048static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003049resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003050 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003051{
Michal Vasko1e62a092015-12-01 12:27:20 +01003052 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01003053 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02003054 const char *id, *prefix, *name;
3055 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02003056 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003057
Michal Vasko184521f2015-09-24 13:14:26 +02003058 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003059 parent_times = 0;
3060 id = path;
3061
3062 do {
3063 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003064 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 +02003065 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003066 }
3067 id += i;
3068
Michal Vasko184521f2015-09-24 13:14:26 +02003069 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003070 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003071 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003072 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01003073 /* get start node */
3074 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003075 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003076 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003077 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003078 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003079 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02003080 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01003081 if (parent_tpdf) {
3082 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejci48464ed2016-03-17 15:44:09 +01003083 LOGVAL(LYE_NORESOLV, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003084 return -1;
3085 }
3086
Radek Krejciadb57612016-02-16 13:34:34 +01003087 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02003088 i = 0;
3089 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003090 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003091 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003092 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003093 }
Michal Vasko58090902015-08-13 14:04:15 +02003094
3095 /* this node is a wrong node, we actually need the augment target */
3096 if (node->nodetype == LYS_AUGMENT) {
3097 node = ((struct lys_node_augment *)node)->target;
3098 if (!node) {
3099 continue;
3100 }
3101 }
3102
3103 ++i;
3104 if (i == parent_times) {
3105 break;
3106 }
3107 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02003108 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003109
Michal Vasko1f76a282015-08-04 16:16:53 +02003110 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02003111 } else {
3112 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003113 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003114 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003115
Michal Vasko184521f2015-09-24 13:14:26 +02003116 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003117 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003118 /* move down the tree, if possible */
3119 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003120 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 +01003121 return -1;
3122 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003123 node = node->child;
3124 }
3125
Michal Vasko4f0dad02016-02-15 14:08:23 +01003126 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003127 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003128 }
3129
Michal Vasko36cbaa42015-12-14 13:15:48 +01003130 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 +02003131 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003132 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003133 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02003134 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003135 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003136 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003137
3138 if (has_predicate) {
3139 /* we have predicate, so the current result must be list */
3140 if (node->nodetype != LYS_LIST) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003141 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003142 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003143 }
3144
Radek Krejci48464ed2016-03-17 15:44:09 +01003145 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003146 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003147 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003148 } else if (i < 0) {
3149 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003150 }
3151 id += i;
3152 }
3153 } while (id[0]);
3154
Radek Krejcib1c12512015-08-11 11:22:04 +02003155 /* the target must be leaf or leaf-list */
3156 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003157 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003158 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003159 }
3160
Radek Krejcicf509982015-12-15 09:22:44 +01003161 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003162 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003163 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003164 return -1;
3165 }
3166
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003167 if (ret) {
3168 *ret = node;
3169 }
3170 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003171}
3172
Michal Vasko730dfdf2015-08-11 14:48:05 +02003173/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003174 * @brief Resolve instance-identifier predicate in JSON data format.
3175 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003176 *
Michal Vaskobb211122015-08-19 14:03:11 +02003177 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003178 * @param[in,out] node_match Nodes matching the restriction without
3179 * the predicate. Nodes not satisfying
3180 * the predicate are removed.
3181 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003182 * @return Number of characters successfully parsed,
3183 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003184 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003185static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003186resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003188 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003189 struct unres_data target_match;
3190 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003191 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003192 const char *model, *name, *value;
3193 char *str;
3194 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3195 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003196
Michal Vasko1f2cc332015-08-19 11:18:32 +02003197 assert(pred && node_match->count);
3198
Michal Vaskocf024702015-10-08 15:01:42 +02003199 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200 idx = -1;
3201 parsed = 0;
3202
3203 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003204 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205 return -parsed+i;
3206 }
3207 parsed += i;
3208 pred += i;
3209
Michal Vasko1f2cc332015-08-19 11:18:32 +02003210 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003211 if (isdigit(name[0])) {
3212 idx = atoi(name);
3213 }
3214
Michal Vasko1f2cc332015-08-19 11:18:32 +02003215 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003216 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003217 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003218 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003219 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003220 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003221 if (!target_match.node) {
3222 LOGMEM;
3223 return -1;
3224 }
Michal Vaskocf024702015-10-08 15:01:42 +02003225 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003226 } else {
3227 str = strndup(model, mod_len);
3228 mod = ly_ctx_get_module(ctx, str, NULL);
3229 free(str);
3230
Radek Krejci804836a2016-02-03 10:39:55 +01003231 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003232 goto remove_instid;
3233 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234 }
3235
3236 /* check that we have the correct type */
3237 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003238 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 goto remove_instid;
3240 }
3241 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003242 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243 goto remove_instid;
3244 }
3245 }
3246
Michal Vasko83a6c462015-10-08 16:43:53 +02003247 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3248 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249 || (!value && (idx != cur_idx))) {
3250 goto remove_instid;
3251 }
3252
Michal Vaskocf024702015-10-08 15:01:42 +02003253 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003254
3255 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003256 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 continue;
3258
3259remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003260 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003261
3262 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003263 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 }
3265 } while (has_predicate);
3266
3267 return parsed;
3268}
3269
Michal Vasko730dfdf2015-08-11 14:48:05 +02003270/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003271 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003272 *
Radek Krejciadb57612016-02-16 13:34:34 +01003273 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003274 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003275 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003276 * @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 +02003277 */
Michal Vasko184521f2015-09-24 13:14:26 +02003278static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003279resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003280{
Radek Krejcic5090c32015-08-12 09:46:19 +02003281 int i = 0, j;
3282 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01003283 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02003284 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003285 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003286 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003287 int mod_len, name_len, has_predicate;
3288 struct unres_data node_match;
3289 uint32_t k;
3290
3291 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003292
Radek Krejcic5090c32015-08-12 09:46:19 +02003293 /* we need root to resolve absolute path */
3294 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003295 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003296 if (data->prev) {
3297 for (; data->prev->next; data = data->prev);
3298 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299
Radek Krejcic5090c32015-08-12 09:46:19 +02003300 /* search for the instance node */
3301 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003302 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003303 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003304 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003305 goto error;
3306 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003307 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003308
Michal Vasko1f2cc332015-08-19 11:18:32 +02003309 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003310 if (!str) {
3311 LOGMEM;
3312 goto error;
3313 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003314 mod = ly_ctx_get_module(ctx, str, NULL);
3315 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003316
Radek Krejcic5090c32015-08-12 09:46:19 +02003317 if (!mod) {
3318 /* no instance exists */
3319 return NULL;
3320 }
3321
Michal Vasko1f2cc332015-08-19 11:18:32 +02003322 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003323 /* no instance exists */
3324 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003325 }
3326
3327 if (has_predicate) {
3328 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003329 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003330 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3331 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3332 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003334 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 continue;
3336 }
3337
3338 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003339 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003340 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003341
Michal Vaskof39142b2015-10-21 11:40:05 +02003342 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003343 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003344 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 goto error;
3346 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003347 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003348
Michal Vasko1f2cc332015-08-19 11:18:32 +02003349 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003350 /* no instance exists */
3351 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003352 }
3353 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354 }
3355
Michal Vasko1f2cc332015-08-19 11:18:32 +02003356 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003357 /* no instance exists */
3358 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003359 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003360 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003361 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003362
Michal Vaskod6adbaa2016-04-11 11:01:09 +02003363 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003364 } else {
3365 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003366 result = node_match.node[0];
3367 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003368
3369 return result;
3370 }
3371
3372error:
3373
3374 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003375 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003376
3377 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003378}
3379
Michal Vasko730dfdf2015-08-11 14:48:05 +02003380/**
3381 * @brief Passes config flag down to children. Does not log.
3382 *
3383 * @param[in] node Parent node.
3384 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003385static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003386inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387{
Radek Krejci1d82ef62015-08-07 14:44:40 +02003388 LY_TREE_FOR(node, node) {
3389 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
3390 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 }
3392}
3393
Michal Vasko730dfdf2015-08-11 14:48:05 +02003394/**
Michal Vasko7178e692016-02-12 15:58:05 +01003395 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003396 *
Michal Vaskobb211122015-08-19 14:03:11 +02003397 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003398 * @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 +02003399 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003400 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003401 */
Michal Vasko7178e692016-02-12 15:58:05 +01003402static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003403resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003405 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003406 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407
Michal Vasko1d87a922015-08-21 12:57:16 +02003408 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409
3410 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003411 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 +01003412 if (rc == -1) {
3413 return -1;
3414 }
3415 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003416 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003417 return -1;
3418 }
3419 if (!aug->target) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003420 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003421 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 }
3423
3424 if (!aug->child) {
3425 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003426 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 return EXIT_SUCCESS;
3428 }
3429
Michal Vaskod58d5962016-03-02 14:29:41 +01003430 /* check for mandatory nodes - if the target node is in another module
3431 * the added nodes cannot be mandatory
3432 */
3433 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3434 && lyp_check_mandatory((struct lys_node *)aug)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003435 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
3436 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 +01003437 return -1;
3438 }
3439
Michal Vasko07e89ef2016-03-03 13:28:57 +01003440 /* check augment target type and then augment nodes type */
3441 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3442 LY_TREE_FOR(aug->child, sub) {
3443 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003444 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3445 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003446 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3447 return -1;
3448 }
3449 }
3450 } else if (aug->target->nodetype == LYS_CHOICE) {
3451 LY_TREE_FOR(aug->child, sub) {
3452 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003453 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3454 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003455 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3456 return -1;
3457 }
3458 }
3459 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003460 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3461 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003462 return -1;
3463 }
3464
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 /* inherit config information from parent, augment does not have
3466 * config property, but we need to keep the information for subelements
3467 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003468 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003469 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 inherit_config_flag(sub);
3471 }
3472
Radek Krejcic071c542016-01-27 14:57:51 +01003473 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003474 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01003475 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003476 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003477 }
3478 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003479 /* reconnect augmenting data into the target - add them to the target child list */
3480 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003481 sub = aug->target->child->prev; /* remember current target's last node */
3482 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003483 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003484 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003485 } else {
3486 aug->target->child = aug->child;
3487 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003488
3489 return EXIT_SUCCESS;
3490}
3491
Michal Vasko730dfdf2015-08-11 14:48:05 +02003492/**
3493 * @brief Resolve uses, apply augments, refines. Logs directly.
3494 *
Michal Vaskobb211122015-08-19 14:03:11 +02003495 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003496 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003497 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003498 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003499 */
Michal Vasko184521f2015-09-24 13:14:26 +02003500static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003501resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502{
3503 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003504 struct lys_node *node = NULL;
3505 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003506 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003507 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003509 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510
Michal Vasko71e1aa82015-08-12 12:17:51 +02003511 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003512 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003513 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003514
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003515 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003516 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01003517 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003518 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003519 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3520 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003521 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003523 }
3524 ctx = uses->module->ctx;
3525
Michal Vaskodef0db12015-10-07 13:22:48 +02003526 /* we managed to copy the grouping, the rest must be possible to resolve */
3527
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 /* apply refines */
3529 for (i = 0; i < uses->refine_size; i++) {
3530 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003531 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcicc217a62016-04-08 16:58:11 +02003532 (const struct lys_node **)&node, 1);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003533 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003534 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003535 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 }
3537
Radek Krejci1d82ef62015-08-07 14:44:40 +02003538 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003539 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3540 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003541 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542 }
3543
3544 /* description on any nodetype */
3545 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003546 lydict_remove(ctx, node->dsc);
3547 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003548 }
3549
3550 /* reference on any nodetype */
3551 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003552 lydict_remove(ctx, node->ref);
3553 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554 }
3555
3556 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003557 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003558 node->flags &= ~LYS_CONFIG_MASK;
3559 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003560 }
3561
3562 /* default value ... */
3563 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003564 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003566 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3567 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3568 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003570 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3571 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003572 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003573 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003574 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003575 }
3576 }
3577 }
3578
3579 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003580 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003581 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003583 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003584
3585 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003586 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587 }
3588 }
3589
3590 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003591 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3592 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3593 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594 }
3595
3596 /* min/max-elements on list or leaf-list */
3597 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003598 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003600 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003601 }
3602 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003603 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003604 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003605 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003606 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003607 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003608 }
3609 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003610 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003611 }
3612 }
3613
3614 /* must in leaf, leaf-list, list, container or anyxml */
3615 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003616 switch (node->nodetype) {
3617 case LYS_LEAF:
3618 old_size = &((struct lys_node_leaf *)node)->must_size;
3619 old_must = &((struct lys_node_leaf *)node)->must;
3620 break;
3621 case LYS_LEAFLIST:
3622 old_size = &((struct lys_node_leaflist *)node)->must_size;
3623 old_must = &((struct lys_node_leaflist *)node)->must;
3624 break;
3625 case LYS_LIST:
3626 old_size = &((struct lys_node_list *)node)->must_size;
3627 old_must = &((struct lys_node_list *)node)->must;
3628 break;
3629 case LYS_CONTAINER:
3630 old_size = &((struct lys_node_container *)node)->must_size;
3631 old_must = &((struct lys_node_container *)node)->must;
3632 break;
3633 case LYS_ANYXML:
3634 old_size = &((struct lys_node_anyxml *)node)->must_size;
3635 old_must = &((struct lys_node_anyxml *)node)->must;
3636 break;
3637 default:
3638 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003639 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003640 }
3641
3642 size = *old_size + rfn->must_size;
3643 must = realloc(*old_must, size * sizeof *rfn->must);
3644 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003646 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003648 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3649 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3650 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3651 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3652 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3653 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654 }
3655
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003656 *old_must = must;
3657 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658 }
3659 }
3660
3661 /* apply augments */
3662 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003663 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003664 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003665 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003666 }
3667 }
3668
3669 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003670}
3671
Michal Vasko730dfdf2015-08-11 14:48:05 +02003672/**
3673 * @brief Resolve base identity recursively. Does not log.
3674 *
3675 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003676 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003677 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003678 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003679 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003680 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003681 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003682static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003683resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003684 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003685{
Michal Vaskof02e3742015-08-05 16:27:02 +02003686 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003687 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003688 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003689
Radek Krejcicf509982015-12-15 09:22:44 +01003690 assert(ret);
3691
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003692 /* search module */
3693 for (i = 0; i < module->ident_size; i++) {
3694 if (!strcmp(basename, module->ident[i].name)) {
3695
3696 if (!ident) {
3697 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003698 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003699 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003700 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003701 }
3702
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003703 base = &module->ident[i];
3704 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705 }
3706 }
3707
3708 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003709 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3710 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3711 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003712
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003713 if (!ident) {
3714 *ret = &module->inc[j].submodule->ident[i];
3715 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003716 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003717
3718 base = &module->inc[j].submodule->ident[i];
3719 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003720 }
3721 }
3722 }
3723
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003724matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003725 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003726 if (base) {
3727 /* check for circular reference */
3728 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3729 if (ident == base_iter) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003730 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
3731 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003732 return EXIT_FAILURE;
3733 }
3734 }
3735 /* checks done, store the result */
3736 ident->base = base;
3737
3738 /* maintain backlinks to the derived identitise */
3739 while (base) {
3740 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003741 if (der) {
3742 der->next = malloc(sizeof *der);
3743 der = der->next;
3744 } else {
3745 ident->base->der = der = malloc(sizeof *der);
3746 }
Michal Vasko253035f2015-12-17 16:58:13 +01003747 if (!der) {
3748 LOGMEM;
3749 return EXIT_FAILURE;
3750 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003751 der->next = NULL;
3752 der->ident = ident;
3753
Radek Krejcibabbff82016-02-19 13:31:37 +01003754 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003755 }
Radek Krejcicf509982015-12-15 09:22:44 +01003756 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003757 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003758 }
3759
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003760 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003761}
3762
Michal Vasko730dfdf2015-08-11 14:48:05 +02003763/**
3764 * @brief Resolve base identity. Logs directly.
3765 *
3766 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003767 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003768 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003769 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01003770 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003771 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003772 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003773 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003774static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003775resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejci48464ed2016-03-17 15:44:09 +01003776 struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003777{
3778 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003779 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003780 struct lys_ident *target, **ret;
3781 uint8_t flags;
3782 struct lys_module *mod;
3783
3784 assert((ident && !type) || (!ident && type));
3785
3786 if (!type) {
3787 /* have ident to resolve */
3788 ret = &target;
3789 flags = ident->flags;
3790 mod = ident->module;
3791 } else {
3792 /* have type to fill */
3793 ret = &type->info.ident.ref;
3794 flags = type->parent->flags;
3795 mod = type->parent->module;
3796 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003797
3798 /* search for the base identity */
3799 name = strchr(basename, ':');
3800 if (name) {
3801 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003802 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803 name++;
3804
Michal Vasko2d851a92015-10-20 16:16:36 +02003805 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003806 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003807 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003808 }
3809 } else {
3810 name = basename;
3811 }
3812
Radek Krejcic071c542016-01-27 14:57:51 +01003813 /* get module where to search */
3814 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3815 if (!module) {
3816 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01003817 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003818 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003819 }
3820
Radek Krejcic071c542016-01-27 14:57:51 +01003821 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003822 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003823 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003824 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003825 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003826 }
Radek Krejcic071c542016-01-27 14:57:51 +01003827 /* and all its submodules */
3828 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3829 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3830 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003831 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003832 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003833 }
3834 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003835
Radek Krejci02a04992016-03-17 16:06:37 +01003836 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, parent);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003837 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003838
3839success:
3840 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003841 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
3842 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003843 return -1;
3844 }
3845
3846 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003847}
3848
Michal Vasko730dfdf2015-08-11 14:48:05 +02003849/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003850 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003851 *
3852 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003853 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01003854 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003855 *
3856 * @return Pointer to the identity resolvent, NULL on error.
3857 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003858struct lys_ident *
Radek Krejci48464ed2016-03-17 15:44:09 +01003859resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003860{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003861 const char *mod_name, *name;
3862 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003863 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003864
Michal Vaskofb0873c2015-08-21 09:00:07 +02003865 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003866 return NULL;
3867 }
3868
Michal Vaskoc633ca02015-08-21 14:03:51 +02003869 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003870 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003871 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003872 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003873 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01003874 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003875 return NULL;
3876 }
3877
Michal Vaskoc633ca02015-08-21 14:03:51 +02003878 if (!strcmp(base->name, name) && (!mod_name
3879 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003880 return base;
3881 }
3882
3883 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003884 if (!strcmp(der->ident->name, name) && (!mod_name
3885 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3886 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003887 /* we have match */
3888 return der->ident;
3889 }
3890 }
3891
Radek Krejci48464ed2016-03-17 15:44:09 +01003892 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003893 return NULL;
3894}
3895
Michal Vasko730dfdf2015-08-11 14:48:05 +02003896/**
Michal Vasko7955b362015-09-04 14:18:15 +02003897 * @brief Resolve (find) choice default case. Does not log.
3898 *
3899 * @param[in] choic Choice to use.
3900 * @param[in] dflt Name of the default case.
3901 *
3902 * @return Pointer to the default node or NULL.
3903 */
3904static struct lys_node *
3905resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3906{
3907 struct lys_node *child, *ret;
3908
3909 LY_TREE_FOR(choic->child, child) {
3910 if (child->nodetype == LYS_USES) {
3911 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3912 if (ret) {
3913 return ret;
3914 }
3915 }
3916
Radek Krejci749190d2016-02-18 16:26:25 +01003917 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003918 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3919 return child;
3920 }
3921 }
3922
3923 return NULL;
3924}
3925
3926/**
Michal Vaskobb211122015-08-19 14:03:11 +02003927 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003928 *
Michal Vaskobb211122015-08-19 14:03:11 +02003929 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003930 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003931 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003932 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003933 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003935resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003936{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003937 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01003938 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003939
Radek Krejci010e54b2016-03-15 09:40:34 +01003940 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
3941 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
3942 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
3943 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
3944 * LYS_USESGRP flag is used. */
3945 for (par_grp = uses->parent; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = par_grp->parent);
Michal Vaskoe91afce2015-08-12 12:21:00 +02003946
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003947 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003948 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3949 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003950 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003951 return -1;
3952 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003953 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003954 return -1;
3955 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003956 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3957 par_grp->nacm++;
3958 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003959 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003960 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003961 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003962 }
3963
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003964 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003965 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3966 par_grp->nacm++;
3967 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003968 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003969 return EXIT_FAILURE;
3970 }
3971
Radek Krejci48464ed2016-03-17 15:44:09 +01003972 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003973 if (!rc) {
3974 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01003975 if (par_grp && (uses->flags & LYS_USESGRP)) {
3976 if (!par_grp->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003977 LOGINT;
3978 return -1;
3979 }
Radek Krejci010e54b2016-03-15 09:40:34 +01003980 par_grp->nacm--;
3981 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003982 }
Radek Krejcicf509982015-12-15 09:22:44 +01003983
3984 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003985 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003986 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003987 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003988 return -1;
3989 }
3990
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003991 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01003992 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
3993 par_grp->nacm++;
3994 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003995 }
3996
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003997 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003998}
3999
Michal Vasko730dfdf2015-08-11 14:48:05 +02004000/**
Michal Vasko9957e592015-08-17 15:04:09 +02004001 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004002 *
Michal Vaskobb211122015-08-19 14:03:11 +02004003 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004004 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004005 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004006 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004007 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004008static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004009resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004010{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004011 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01004012 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004013
4014 for (i = 0; i < list->keys_size; ++i) {
4015 /* get the key name */
4016 if ((value = strpbrk(keys_str, " \t\n"))) {
4017 len = value - keys_str;
4018 while (isspace(value[0])) {
4019 value++;
4020 }
4021 } else {
4022 len = strlen(keys_str);
4023 }
4024
Michal Vasko4f0dad02016-02-15 14:08:23 +01004025 rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004026 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004027 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004028 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004029 }
4030 return rc;
4031 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004032
Radek Krejci48464ed2016-03-17 15:44:09 +01004033 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004034 /* check_key logs */
4035 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036 }
4037
Radek Krejcicf509982015-12-15 09:22:44 +01004038 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004039 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004040 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
4041 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01004042 return -1;
4043 }
4044
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004045 /* prepare for next iteration */
4046 while (value && isspace(value[0])) {
4047 value++;
4048 }
4049 keys_str = value;
4050 }
4051
Michal Vaskof02e3742015-08-05 16:27:02 +02004052 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004053}
4054
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004055/**
Michal Vaskobf19d252015-10-08 15:39:17 +02004056 * @brief Resolve (check) all must conditions of \p node.
4057 * Logs directly.
4058 *
4059 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02004060 *
4061 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
4062 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004063static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004064resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02004065{
Michal Vaskobf19d252015-10-08 15:39:17 +02004066 uint8_t i, must_size;
4067 struct lys_restr *must;
4068 struct lyxp_set set;
4069
4070 assert(node);
4071 memset(&set, 0, sizeof set);
4072
4073 switch (node->schema->nodetype) {
4074 case LYS_CONTAINER:
4075 must_size = ((struct lys_node_container *)node->schema)->must_size;
4076 must = ((struct lys_node_container *)node->schema)->must;
4077 break;
4078 case LYS_LEAF:
4079 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
4080 must = ((struct lys_node_leaf *)node->schema)->must;
4081 break;
4082 case LYS_LEAFLIST:
4083 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
4084 must = ((struct lys_node_leaflist *)node->schema)->must;
4085 break;
4086 case LYS_LIST:
4087 must_size = ((struct lys_node_list *)node->schema)->must_size;
4088 must = ((struct lys_node_list *)node->schema)->must;
4089 break;
4090 case LYS_ANYXML:
4091 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
4092 must = ((struct lys_node_anyxml *)node->schema)->must;
4093 break;
4094 default:
4095 must_size = 0;
4096 break;
4097 }
4098
4099 for (i = 0; i < must_size; ++i) {
Michal Vasko944a5642016-03-21 11:48:58 +01004100 if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004101 return -1;
4102 }
4103
Michal Vasko944a5642016-03-21 11:48:58 +01004104 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02004105
4106 if (!set.value.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02004107 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
4108 if (must[i].emsg) {
4109 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
4110 }
4111 if (must[i].eapptag) {
4112 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
4113 }
Michal Vaskobf19d252015-10-08 15:39:17 +02004114 return 1;
4115 }
4116 }
4117
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004118 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02004119}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004120
Michal Vaskobf19d252015-10-08 15:39:17 +02004121/**
Michal Vaskocf024702015-10-08 15:01:42 +02004122 * @brief Resolve (find) when condition context node. Does not log.
4123 *
4124 * @param[in] node Data node, whose conditional definition is being decided.
4125 * @param[in] schema Schema node with a when condition.
4126 *
4127 * @return Context node.
4128 */
4129static struct lyd_node *
4130resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004131{
Michal Vaskocf024702015-10-08 15:01:42 +02004132 struct lyd_node *parent;
4133 struct lys_node *sparent;
4134 uint16_t i, data_depth, schema_depth;
4135
4136 /* find a not schema-only node */
4137 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
4138 schema = lys_parent(schema);
4139 if (!schema) {
4140 return NULL;
4141 }
4142 }
4143
4144 /* get node depths */
4145 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
4146 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
4147 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
4148 ++schema_depth;
4149 }
4150 }
4151 if (data_depth < schema_depth) {
4152 return NULL;
4153 }
4154
4155 /* find the corresponding data node */
4156 for (i = 0; i < data_depth - schema_depth; ++i) {
4157 node = node->parent;
4158 }
4159 if (node->schema != schema) {
4160 return NULL;
4161 }
4162
4163 return node;
4164}
4165
Radek Krejci03b71f72016-03-16 11:10:09 +01004166int
Radek Krejci01696bf2016-03-18 13:19:36 +01004167resolve_applies_must(const struct lyd_node *node)
4168{
4169 switch (node->schema->nodetype) {
4170 case LYS_CONTAINER:
4171 return ((struct lys_node_container *)node->schema)->must_size;
4172 case LYS_LEAF:
4173 return ((struct lys_node_leaf *)node->schema)->must_size;
4174 case LYS_LEAFLIST:
4175 return ((struct lys_node_leaflist *)node->schema)->must_size;
4176 case LYS_LIST:
4177 return ((struct lys_node_list *)node->schema)->must_size;
4178 case LYS_ANYXML:
4179 return ((struct lys_node_anyxml *)node->schema)->must_size;
4180 default:
4181 return 0;
4182 }
4183}
4184
4185int
Radek Krejci03b71f72016-03-16 11:10:09 +01004186resolve_applies_when(const struct lyd_node *node)
4187{
4188 struct lys_node *parent;
4189
4190 assert(node);
4191
4192 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
4193 return 1;
4194 }
4195
4196 parent = node->schema;
4197 goto check_augment;
4198
4199 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4200 if (((struct lys_node_uses *)parent)->when) {
4201 return 1;
4202 }
4203check_augment:
4204
4205 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
4206 (((struct lys_node_augment *)parent->parent)->when))) {
4207
4208 }
4209 parent = lys_parent(parent);
4210 }
4211
4212 return 0;
4213}
4214
Michal Vaskocf024702015-10-08 15:01:42 +02004215/**
4216 * @brief Resolve (check) all when conditions relevant for \p node.
4217 * Logs directly.
4218 *
4219 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02004220 *
Radek Krejci03b71f72016-03-16 11:10:09 +01004221 * @return
4222 * -1 - error, ly_errno is set
4223 * 0 - true "when" statement
4224 * 0, ly_vecode = LYVE_NOCOND - false "when" statement
4225 * 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 +02004226 */
4227static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004228resolve_when(struct lyd_node *node)
Michal Vaskocf024702015-10-08 15:01:42 +02004229{
4230 struct lyd_node *ctx_node = NULL;
4231 struct lys_node *parent;
4232 struct lyxp_set set;
Radek Krejci51093642016-03-29 10:14:59 +02004233 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02004234
4235 assert(node);
4236 memset(&set, 0, sizeof set);
4237
4238 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko944a5642016-03-21 11:48:58 +01004239 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004240 if (rc) {
4241 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004242 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004243 }
Radek Krejci51093642016-03-29 10:14:59 +02004244 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004245 }
4246
Radek Krejci03b71f72016-03-16 11:10:09 +01004247 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01004248 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004249 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004250 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004251 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004252 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004253 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004254 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004255 }
Radek Krejci51093642016-03-29 10:14:59 +02004256
4257 /* free xpath set content */
4258 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004259 }
4260
4261 parent = node->schema;
4262 goto check_augment;
4263
4264 /* check when in every schema node that affects node */
4265 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4266 if (((struct lys_node_uses *)parent)->when) {
4267 if (!ctx_node) {
4268 ctx_node = resolve_when_ctx_node(node, parent);
4269 if (!ctx_node) {
4270 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004271 rc = -1;
4272 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004273 }
4274 }
Michal Vasko944a5642016-03-21 11:48:58 +01004275 rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004276 if (rc) {
4277 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004278 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004279 }
Radek Krejci51093642016-03-29 10:14:59 +02004280 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004281 }
4282
Michal Vasko944a5642016-03-21 11:48:58 +01004283 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004284 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004285 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004286 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004287 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004288 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004289 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004290 }
Radek Krejci51093642016-03-29 10:14:59 +02004291
4292 /* free xpath set content */
4293 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004294 }
4295
4296check_augment:
4297 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
4298 if (!ctx_node) {
4299 ctx_node = resolve_when_ctx_node(node, parent->parent);
4300 if (!ctx_node) {
4301 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004302 rc = -1;
4303 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004304 }
4305 }
Michal Vasko944a5642016-03-21 11:48:58 +01004306 rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004307 if (rc) {
4308 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004309 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004310 }
Radek Krejci51093642016-03-29 10:14:59 +02004311 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004312 }
4313
Michal Vasko944a5642016-03-21 11:48:58 +01004314 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004315
4316 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004317 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004318 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004319 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004320 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004321 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004322 }
Radek Krejci51093642016-03-29 10:14:59 +02004323
4324 /* free xpath set content */
4325 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004326 }
4327
4328 parent = lys_parent(parent);
4329 }
4330
Radek Krejci0b7704f2016-03-18 12:16:14 +01004331 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01004332
Radek Krejci51093642016-03-29 10:14:59 +02004333cleanup:
4334
4335 /* free xpath set content */
4336 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
4337
4338 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004339}
4340
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004341/**
Michal Vaskobb211122015-08-19 14:03:11 +02004342 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004343 *
4344 * @param[in] mod Main module.
4345 * @param[in] item Item to resolve. Type determined by \p type.
4346 * @param[in] type Type of the unresolved item.
4347 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02004348 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004349 *
4350 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4351 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004352static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004353resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01004354 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004355{
Radek Krejci4f78b532016-02-17 13:43:00 +01004356 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02004357 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004358 const char *base_name;
4359
4360 struct lys_ident *ident;
4361 struct lys_type *stype;
4362 struct lys_feature **feat_ptr;
4363 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01004364 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004365 struct yang_type *yang;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004366
4367 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004368 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004369 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004370 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004371 ident = item;
4372
Radek Krejci48464ed2016-03-17 15:44:09 +01004373 rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004374 break;
4375 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004376 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004377 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004378 stype = item;
4379
Radek Krejci48464ed2016-03-17 15:44:09 +01004380 rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004381 break;
4382 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02004383 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004384 stype = item;
4385
Radek Krejci2f12f852016-01-08 12:59:57 +01004386 /* HACK - when there is no parent, we are in top level typedef and in that
4387 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
4388 * know it via tpdf_flag */
4389 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01004390 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01004391 node = (struct lys_node *)stype->parent;
4392 }
4393
Radek Krejci48464ed2016-03-17 15:44:09 +01004394 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01004395 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01004396 if (stype->info.lref.target) {
4397 /* store the backlink from leafref target */
4398 if (!stype->info.lref.target->child) {
4399 stype->info.lref.target->child = (void*)ly_set_new();
4400 if (!stype->info.lref.target->child) {
4401 LOGMEM;
4402 return -1;
4403 }
4404 }
4405 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
4406 }
4407
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004408 break;
4409 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004410 /* parent */
4411 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004412 stype = item;
4413
Michal Vasko88c29542015-11-27 14:57:53 +01004414 /* HACK type->der is temporarily unparsed type statement */
4415 yin = (struct lyxml_elem *)stype->der;
4416 stype->der = NULL;
4417
Pavol Vicana0e4e672016-02-24 12:20:04 +01004418 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4419 yang = (struct yang_type *)yin;
4420 rc = yang_check_type(mod, node, yang, unres);
4421
4422 if (rc) {
Pavol Vican933aa5a2016-04-09 21:05:46 +02004423 if (rc == -1) {
4424 yang->type->base = yang->base;
4425 lydict_remove(mod->ctx, yang->name);
4426 free(yang);
4427 stype->der = NULL;
4428 } else {
4429 /* may try again later */
4430 stype->der = (struct lys_tpdf *)yang;
4431 }
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004432 } else {
4433 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02004434 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004435 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01004436 }
4437
Michal Vasko88c29542015-11-27 14:57:53 +01004438 } else {
Pavol Vicana0e4e672016-02-24 12:20:04 +01004439 rc = fill_yin_type(mod, node, yin, stype, unres);
4440 if (!rc) {
4441 /* we need to always be able to free this, it's safe only in this case */
4442 lyxml_free(mod->ctx, yin);
4443 } else {
4444 /* may try again later, put all back how it was */
4445 stype->der = (struct lys_tpdf *)yin;
4446 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004447 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004448 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004449 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004450 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004451 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004452 feat_ptr = item;
4453
Radek Krejci48464ed2016-03-17 15:44:09 +01004454 rc = resolve_feature(base_name, mod, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004455 break;
4456 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004457 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004458 break;
4459 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004460 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004461 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004462 stype = item;
4463
Radek Krejci48464ed2016-03-17 15:44:09 +01004464 rc = check_default(stype, base_name, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004465 break;
4466 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004467 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004468 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004469 choic = item;
4470
Michal Vasko7955b362015-09-04 14:18:15 +02004471 choic->dflt = resolve_choice_dflt(choic, base_name);
4472 if (choic->dflt) {
4473 rc = EXIT_SUCCESS;
4474 } else {
4475 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004476 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004477 break;
4478 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004479 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004480 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004481 break;
4482 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004483 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004484 rc = resolve_unique(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004485 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004486 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004487 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01004488 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004489 default:
4490 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004491 break;
4492 }
4493
Radek Krejci4f78b532016-02-17 13:43:00 +01004494 if (has_str && !rc) {
4495 lydict_remove(mod->ctx, str_snode);
4496 }
4497
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004498 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004499}
4500
Michal Vaskof02e3742015-08-05 16:27:02 +02004501/* logs directly */
4502static void
Radek Krejci48464ed2016-03-17 15:44:09 +01004503print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004504{
Michal Vaskof02e3742015-08-05 16:27:02 +02004505 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004506 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004507 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004508 break;
4509 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004510 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004511 break;
4512 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004513 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
4514 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02004515 break;
4516 case UNRES_TYPE_DER:
Radek Krejci48464ed2016-03-17 15:44:09 +01004517 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type",
4518 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value);
Michal Vaskof02e3742015-08-05 16:27:02 +02004519 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004520 case UNRES_IFFEAT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004521 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004522 break;
4523 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004524 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004525 break;
4526 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004527 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004528 break;
4529 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004530 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004531 break;
4532 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01004533 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004534 break;
4535 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01004536 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004537 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004538 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004539 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
4540 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01004541 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004542 default:
4543 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004544 break;
4545 }
4546}
4547
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004548/**
Michal Vaskobb211122015-08-19 14:03:11 +02004549 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004550 *
4551 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004552 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004553 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004554 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004555 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004556int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004557resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004558{
Radek Krejci010e54b2016-03-15 09:40:34 +01004559 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004560 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004561
4562 assert(unres);
4563
Radek Krejci010e54b2016-03-15 09:40:34 +01004564 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4565 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02004566
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004567 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004568 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004569 unres_count = 0;
4570 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004571
4572 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01004573 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
4574 * we need every type's base only */
4575 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004576 continue;
4577 }
4578
Michal Vasko88c29542015-11-27 14:57:53 +01004579 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01004580 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004581 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004582 unres->type[i] = UNRES_RESOLVED;
4583 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004584 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004585 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004586 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004587 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004588 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004589 }
Michal Vasko88c29542015-11-27 14:57:53 +01004590 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004591
Michal Vasko88c29542015-11-27 14:57:53 +01004592 if (res_count < unres_count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004593 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004594 }
4595
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 /* the rest */
4597 for (i = 0; i < unres->count; ++i) {
4598 if (unres->type[i] == UNRES_RESOLVED) {
4599 continue;
4600 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004601
Radek Krejci48464ed2016-03-17 15:44:09 +01004602 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004603 if (rc == 0) {
4604 unres->type[i] = UNRES_RESOLVED;
4605 ++resolved;
4606 } else if (rc == -1) {
4607 ly_vlog_hide(0);
Michal Vasko184521f2015-09-24 13:14:26 +02004608 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004609 }
4610 }
4611
Radek Krejci010e54b2016-03-15 09:40:34 +01004612 ly_vlog_hide(0);
4613
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004614 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004615 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
4616 * all the validation errors
4617 */
4618 for (i = 0; i < unres->count; ++i) {
4619 if (unres->type[i] == UNRES_RESOLVED) {
4620 continue;
4621 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004622 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004623 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004624 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004625 }
4626
Radek Krejci010e54b2016-03-15 09:40:34 +01004627 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4628
Radek Krejcic071c542016-01-27 14:57:51 +01004629 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004630 return EXIT_SUCCESS;
4631}
4632
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004633/**
Michal Vaskobb211122015-08-19 14:03:11 +02004634 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004635 *
4636 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004637 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004638 * @param[in] item Item to resolve. Type determined by \p type.
4639 * @param[in] type Type of the unresolved item.
4640 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004641 *
4642 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4643 */
4644int
Radek Krejci48464ed2016-03-17 15:44:09 +01004645unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
4646 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004647{
Radek Krejci48464ed2016-03-17 15:44:09 +01004648 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 +02004649}
4650
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004651/**
Michal Vaskobb211122015-08-19 14:03:11 +02004652 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004653 *
4654 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004655 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004656 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004657 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004658 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004659 *
4660 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4661 */
4662int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004663unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01004664 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004665{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004666 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004667 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01004668 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004669
Michal Vasko9bf425b2015-10-22 11:42:03 +02004670 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4671 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004672
Radek Krejci010e54b2016-03-15 09:40:34 +01004673 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004674 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004675 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004676 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004677 if (rc == -1 && ly_errno == LY_EVALID) {
4678 path = strdup(ly_errpath());
4679 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
4680 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
4681 free(path);
4682 free(msg);
4683 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004684 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004685 }
4686
Radek Krejci48464ed2016-03-17 15:44:09 +01004687 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02004688
Michal Vasko88c29542015-11-27 14:57:53 +01004689 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4690 if (type == UNRES_TYPE_DER) {
4691 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004692 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
4693 lyxml_unlink_elem(mod->ctx, yin, 1);
4694 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4695 }
Michal Vasko88c29542015-11-27 14:57:53 +01004696 }
4697
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004698 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004699 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4700 if (!unres->item) {
4701 LOGMEM;
4702 return -1;
4703 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004704 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004705 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4706 if (!unres->type) {
4707 LOGMEM;
4708 return -1;
4709 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004710 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004711 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4712 if (!unres->str_snode) {
4713 LOGMEM;
4714 return -1;
4715 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004716 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004717 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4718 if (!unres->module) {
4719 LOGMEM;
4720 return -1;
4721 }
4722 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004723
4724 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004725}
4726
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004727/**
Michal Vaskobb211122015-08-19 14:03:11 +02004728 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004729 *
4730 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004731 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004732 * @param[in] item Old item to be resolved.
4733 * @param[in] type Type of the old unresolved item.
4734 * @param[in] new_item New item to use in the duplicate.
4735 *
4736 * @return EXIT_SUCCESS on success, -1 on error.
4737 */
Michal Vaskodad19402015-08-06 09:51:53 +02004738int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004739unres_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 +02004740{
4741 int i;
4742
Michal Vaskocf024702015-10-08 15:01:42 +02004743 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004744
Michal Vasko0bd29d12015-08-19 11:45:49 +02004745 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004746
4747 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004748 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004749 }
4750
Michal Vasko0d204592015-10-07 09:50:04 +02004751 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004752 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004753 LOGINT;
4754 return -1;
4755 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004756 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004757 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004758 LOGINT;
4759 return -1;
4760 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004761 }
Michal Vaskodad19402015-08-06 09:51:53 +02004762
4763 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004764}
4765
Michal Vaskof02e3742015-08-05 16:27:02 +02004766/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004767int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004768unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004769{
4770 uint32_t ret = -1, i;
4771
4772 for (i = 0; i < unres->count; ++i) {
4773 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4774 ret = i;
4775 break;
4776 }
4777 }
4778
4779 return ret;
4780}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004781
Michal Vasko88c29542015-11-27 14:57:53 +01004782void
Radek Krejcic071c542016-01-27 14:57:51 +01004783unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004784{
4785 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004786 unsigned int unresolved = 0;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004787 struct lyxml_elem *yin;
4788 struct yang_type *yang;
Michal Vasko88c29542015-11-27 14:57:53 +01004789
Radek Krejcic071c542016-01-27 14:57:51 +01004790 if (!unres || !(*unres)) {
4791 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004792 }
4793
Radek Krejcic071c542016-01-27 14:57:51 +01004794 assert(module || (*unres)->count == 0);
4795
4796 for (i = 0; i < (*unres)->count; ++i) {
4797 if ((*unres)->module[i] != module) {
4798 if ((*unres)->type[i] != UNRES_RESOLVED) {
4799 unresolved++;
4800 }
4801 continue;
4802 }
4803 if ((*unres)->type[i] == UNRES_TYPE_DER) {
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004804 yin = (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der;
4805 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4806 yang =(struct yang_type *)yin;
Pavol Vican6b072512016-04-04 10:50:21 +02004807 yang->type->base = yang->base;
Pavol Vican5f0316a2016-04-05 21:21:11 +02004808 lydict_remove(module->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004809 free(yang);
4810 } else {
4811 lyxml_free(module->ctx, yin);
4812 }
Radek Krejcic071c542016-01-27 14:57:51 +01004813 }
4814 (*unres)->type[i] = UNRES_RESOLVED;
4815 }
4816
4817 if (!module || (!unresolved && !module->type)) {
4818 free((*unres)->item);
4819 free((*unres)->type);
4820 free((*unres)->str_snode);
4821 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01004822 free((*unres));
4823 (*unres) = NULL;
4824 }
Michal Vasko88c29542015-11-27 14:57:53 +01004825}
4826
Michal Vasko8bcdf292015-08-19 14:04:43 +02004827/**
4828 * @brief Resolve a single unres data item. Logs directly.
4829 *
Michal Vaskocf024702015-10-08 15:01:42 +02004830 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02004831 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004832 *
4833 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4834 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004835int
Radek Krejci48464ed2016-03-17 15:44:09 +01004836resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004837{
4838 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004839 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004840 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004841 struct lys_node_leaf *sleaf;
4842 struct unres_data matches;
4843
4844 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004845 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004846 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004847
Michal Vaskocf024702015-10-08 15:01:42 +02004848 switch (type) {
4849 case UNRES_LEAFREF:
4850 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vasko2471e7f2016-04-11 11:00:15 +02004851 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
4852 if (resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches) == -1) {
4853 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004854 }
4855
4856 /* check that value matches */
4857 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004858 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004859 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004860 break;
4861 }
4862 }
4863
Michal Vaskocf024702015-10-08 15:01:42 +02004864 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004865 memset(&matches, 0, sizeof matches);
4866
Michal Vaskocf024702015-10-08 15:01:42 +02004867 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004868 /* reference not found */
Michal Vasko6ac68282016-04-11 10:56:47 +02004869 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004870 return EXIT_FAILURE;
4871 }
Michal Vaskocf024702015-10-08 15:01:42 +02004872 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004873
Michal Vaskocf024702015-10-08 15:01:42 +02004874 case UNRES_INSTID:
4875 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004876 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01004877 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01004878 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004879 if (ly_errno) {
4880 return -1;
4881 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02004882 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004883 return EXIT_FAILURE;
4884 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004885 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004886 }
4887 }
Michal Vaskocf024702015-10-08 15:01:42 +02004888 break;
4889
4890 case UNRES_WHEN:
Radek Krejci48464ed2016-03-17 15:44:09 +01004891 if ((rc = resolve_when(node))) {
Michal Vaskocf024702015-10-08 15:01:42 +02004892 return rc;
4893 }
4894 break;
4895
Michal Vaskobf19d252015-10-08 15:39:17 +02004896 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01004897 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004898 return rc;
4899 }
4900 break;
4901
Michal Vaskocf024702015-10-08 15:01:42 +02004902 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004903 LOGINT;
4904 return -1;
4905 }
4906
4907 return EXIT_SUCCESS;
4908}
4909
4910/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01004911 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02004912 *
4913 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004914 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004915 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01004916 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004917 */
4918int
Radek Krejci0b7704f2016-03-18 12:16:14 +01004919unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004920{
Radek Krejci03b71f72016-03-16 11:10:09 +01004921 assert(unres && node);
4922 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004923
Radek Krejci03b71f72016-03-16 11:10:09 +01004924 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004925 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4926 if (!unres->node) {
4927 LOGMEM;
4928 return -1;
4929 }
Michal Vaskocf024702015-10-08 15:01:42 +02004930 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004931 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4932 if (!unres->type) {
4933 LOGMEM;
4934 return -1;
4935 }
Michal Vaskocf024702015-10-08 15:01:42 +02004936 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004937
Radek Krejci0b7704f2016-03-18 12:16:14 +01004938 if (type == UNRES_WHEN) {
4939 /* remove previous result */
4940 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004941 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004942
4943 return EXIT_SUCCESS;
4944}
4945
4946/**
4947 * @brief Resolve every unres data item in the structure. Logs directly.
4948 *
4949 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01004950 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
4951 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01004952 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004953 *
4954 * @return EXIT_SUCCESS on success, -1 on error.
4955 */
4956int
Radek Krejci0c0086a2016-03-24 15:20:28 +01004957resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004958{
Radek Krejci0c0086a2016-03-24 15:20:28 +01004959 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01004960 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01004961 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004962 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963
Radek Krejci03b71f72016-03-16 11:10:09 +01004964 assert(unres);
Radek Krejci8ee1b562016-03-31 10:58:31 +02004965 assert((root && (*root)) || (options & LYD_OPT_NOAUTODEL));
Radek Krejci03b71f72016-03-16 11:10:09 +01004966
4967 if (!unres->count) {
4968 return EXIT_SUCCESS;
4969 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004970
Radek Krejci010e54b2016-03-15 09:40:34 +01004971 LOGVRB("Resolving unresolved data nodes and their constraints.");
4972 ly_vlog_hide(1);
4973
Radek Krejci0b7704f2016-03-18 12:16:14 +01004974 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01004975 ly_errno = LY_SUCCESS;
4976 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004977 do {
4978 progress = 0;
4979 for(i = 0; i < unres->count; i++) {
4980 if (unres->type[i] != UNRES_WHEN) {
4981 continue;
4982 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004983 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004984 /* count when-stmt nodes in unres list */
4985 when_stmt++;
4986 }
4987
4988 /* resolve when condition only when all parent when conditions are already resolved */
4989 for (parent = unres->node[i]->parent;
4990 parent && LYD_WHEN_DONE(parent->when_status);
4991 parent = parent->parent) {
4992 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
4993 /* the parent node was already unlinked, do not resolve this node,
4994 * it will be removed anyway, so just mark it as resolved
4995 */
4996 unres->node[i]->when_status |= LYD_WHEN_FALSE;
4997 unres->type[i] = UNRES_RESOLVED;
4998 resolved++;
4999 break;
5000 }
5001 }
5002 if (parent) {
5003 continue;
5004 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005005
Radek Krejci48464ed2016-03-17 15:44:09 +01005006 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005007 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005008 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
5009 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005010 /* false when condition */
5011 ly_vlog_hide(0);
5012 path = strdup(ly_errpath());
5013 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
5014 path[0] ? path : "", path[0] ? ")" : "");
5015 free(path);
5016 free(msg);
5017 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005018 } /* follows else */
5019
Radek Krejci0c0086a2016-03-24 15:20:28 +01005020 /* only unlink now, the subtree can contain another nodes stored in the unres list */
5021 /* if it has parent non-presence containers that would be empty, we should actually
5022 * remove the container
5023 */
5024 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
5025 for (parent = unres->node[i];
5026 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
5027 parent = parent->parent) {
5028 if (((struct lys_node_container *)parent->parent->schema)->presence) {
5029 /* presence container */
5030 break;
5031 }
5032 if (parent->next || parent->prev != parent) {
5033 /* non empty (the child we are in and we are going to remove is not the only child) */
5034 break;
5035 }
5036 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005037 unres->node[i] = parent;
5038 }
5039
Radek Krejci0b7704f2016-03-18 12:16:14 +01005040 /* auto-delete */
5041 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
5042 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01005043 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005044 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01005045 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005046
Radek Krejci0b7704f2016-03-18 12:16:14 +01005047 lyd_unlink(unres->node[i]);
5048 unres->type[i] = UNRES_DELETE;
5049 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01005050
5051 /* update the rest of unres items */
5052 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01005053 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01005054 continue;
5055 }
5056
5057 /* test if the node is in subtree to be deleted */
5058 for (parent = unres->node[j]; parent; parent = parent->parent) {
5059 if (parent == unres->node[i]) {
5060 /* yes, it is */
5061 unres->type[j] = UNRES_RESOLVED;
5062 resolved++;
5063 break;
5064 }
5065 }
5066 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005067 } else {
5068 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01005069 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005070 ly_errno = LY_SUCCESS;
5071 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005072 resolved++;
5073 progress = 1;
5074 } else if (rc == -1) {
5075 ly_vlog_hide(0);
5076 return -1;
5077 }
5078 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005079 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005080 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01005081
Radek Krejci0b7704f2016-03-18 12:16:14 +01005082 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01005083 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005084 ly_vlog_hide(0);
5085 path = strdup(ly_errpath());
5086 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
5087 path[0] ? path : "", path[0] ? ")" : "");
5088 free(path);
5089 free(msg);
5090 return -1;
5091 }
5092
5093 for (i = 0; del_items && i < unres->count; i++) {
5094 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
5095 if (unres->type[i] != UNRES_DELETE) {
5096 continue;
5097 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005098 if (!unres->node[i]) {
5099 unres->type[i] = UNRES_RESOLVED;
5100 del_items--;
5101 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005102 }
5103
5104 /* really remove the complete subtree */
5105 lyd_free(unres->node[i]);
5106 unres->type[i] = UNRES_RESOLVED;
5107 del_items--;
5108 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005109
5110 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005111 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005112 if (unres->type[i] == UNRES_RESOLVED) {
5113 continue;
5114 }
5115
Radek Krejci48464ed2016-03-17 15:44:09 +01005116 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005117 if (rc == 0) {
5118 unres->type[i] = UNRES_RESOLVED;
5119 resolved++;
5120 } else if (rc == -1) {
5121 ly_vlog_hide(0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005122 return -1;
5123 }
5124 }
5125
Radek Krejci010e54b2016-03-15 09:40:34 +01005126 ly_vlog_hide(0);
5127 if (resolved < unres->count) {
5128 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
5129 * all the validation errors
5130 */
5131 for (i = 0; i < unres->count; ++i) {
5132 if (unres->type[i] == UNRES_RESOLVED) {
5133 continue;
5134 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005135 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005136 }
5137 return -1;
5138 }
5139
5140 LOGVRB("All data nodes and constraints resolved");
5141 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005142 return EXIT_SUCCESS;
5143}