blob: 9558fc28aca651fbf92692c0c2b976d899c1bee4 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
32
Michal Vasko730dfdf2015-08-11 14:48:05 +020033/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020034 * @brief Parse an identifier.
35 *
36 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
37 * identifier = (ALPHA / "_")
38 * *(ALPHA / DIGIT / "_" / "-" / ".")
39 *
Michal Vaskobb211122015-08-19 14:03:11 +020040 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020041 *
42 * @return Number of characters successfully parsed.
43 */
Michal Vasko249e6b52015-08-19 11:08:52 +020044int
Radek Krejci6dc53a22015-08-17 13:27:59 +020045parse_identifier(const char *id)
46{
47 int parsed = 0;
48
Michal Vasko1ab90bc2016-03-15 10:40:22 +010049 assert(id);
50
Radek Krejci6dc53a22015-08-17 13:27:59 +020051 if (((id[0] == 'x') || (id[0] == 'X'))
Michal Vasko1ab90bc2016-03-15 10:40:22 +010052 && (id[0] && ((id[1] == 'm') || (id[0] == 'M')))
53 && (id[1] && ((id[2] == 'l') || (id[2] == 'L')))) {
Radek Krejci6dc53a22015-08-17 13:27:59 +020054 return -parsed;
55 }
56
57 if (!isalpha(id[0]) && (id[0] != '_')) {
58 return -parsed;
59 }
60
61 ++parsed;
62 ++id;
63
64 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
65 ++parsed;
66 ++id;
67 }
68
69 return parsed;
70}
71
72/**
73 * @brief Parse a node-identifier.
74 *
Michal Vasko723e50c2015-10-20 15:20:29 +020075 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020076 *
Michal Vaskobb211122015-08-19 14:03:11 +020077 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020078 * @param[out] mod_name Points to the module name, NULL if there is not any.
79 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020080 * @param[out] name Points to the node name.
81 * @param[out] nam_len Length of the node name.
82 *
83 * @return Number of characters successfully parsed,
84 * positive on success, negative on failure.
85 */
86static int
Michal Vasko723e50c2015-10-20 15:20:29 +020087parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +020088{
89 int parsed = 0, ret;
90
91 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020092 if (mod_name) {
93 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020094 }
Michal Vasko723e50c2015-10-20 15:20:29 +020095 if (mod_name_len) {
96 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020097 }
98 if (name) {
99 *name = NULL;
100 }
101 if (nam_len) {
102 *nam_len = 0;
103 }
104
105 if ((ret = parse_identifier(id)) < 1) {
106 return ret;
107 }
108
Michal Vasko723e50c2015-10-20 15:20:29 +0200109 if (mod_name) {
110 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200111 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200112 if (mod_name_len) {
113 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114 }
115
116 parsed += ret;
117 id += ret;
118
119 /* there is prefix */
120 if (id[0] == ':') {
121 ++parsed;
122 ++id;
123
124 /* there isn't */
125 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200126 if (name && mod_name) {
127 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200128 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200129 if (mod_name) {
130 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200131 }
132
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (nam_len && mod_name_len) {
134 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 if (mod_name_len) {
137 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200138 }
139
140 return parsed;
141 }
142
143 /* identifier (node name) */
144 if ((ret = parse_identifier(id)) < 1) {
145 return -parsed+ret;
146 }
147
148 if (name) {
149 *name = id;
150 }
151 if (nam_len) {
152 *nam_len = ret;
153 }
154
155 return parsed+ret;
156}
157
158/**
159 * @brief Parse a path-predicate (leafref).
160 *
161 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
162 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
163 *
Michal Vaskobb211122015-08-19 14:03:11 +0200164 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200165 * @param[out] prefix Points to the prefix, NULL if there is not any.
166 * @param[out] pref_len Length of the prefix, 0 if there is not any.
167 * @param[out] name Points to the node name.
168 * @param[out] nam_len Length of the node name.
169 * @param[out] path_key_expr Points to the path-key-expr.
170 * @param[out] pke_len Length of the path-key-expr.
171 * @param[out] has_predicate Flag to mark whether there is another predicate following.
172 *
173 * @return Number of characters successfully parsed,
174 * positive on success, negative on failure.
175 */
176static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200177parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
178 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200179{
180 const char *ptr;
181 int parsed = 0, ret;
182
183 assert(id);
184 if (prefix) {
185 *prefix = NULL;
186 }
187 if (pref_len) {
188 *pref_len = 0;
189 }
190 if (name) {
191 *name = NULL;
192 }
193 if (nam_len) {
194 *nam_len = 0;
195 }
196 if (path_key_expr) {
197 *path_key_expr = NULL;
198 }
199 if (pke_len) {
200 *pke_len = 0;
201 }
202 if (has_predicate) {
203 *has_predicate = 0;
204 }
205
206 if (id[0] != '[') {
207 return -parsed;
208 }
209
210 ++parsed;
211 ++id;
212
213 while (isspace(id[0])) {
214 ++parsed;
215 ++id;
216 }
217
218 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
219 return -parsed+ret;
220 }
221
222 parsed += ret;
223 id += ret;
224
225 while (isspace(id[0])) {
226 ++parsed;
227 ++id;
228 }
229
230 if (id[0] != '=') {
231 return -parsed;
232 }
233
234 ++parsed;
235 ++id;
236
237 while (isspace(id[0])) {
238 ++parsed;
239 ++id;
240 }
241
242 if ((ptr = strchr(id, ']')) == NULL) {
243 return -parsed;
244 }
245
246 --ptr;
247 while (isspace(ptr[0])) {
248 --ptr;
249 }
250 ++ptr;
251
252 ret = ptr-id;
253 if (path_key_expr) {
254 *path_key_expr = id;
255 }
256 if (pke_len) {
257 *pke_len = ret;
258 }
259
260 parsed += ret;
261 id += ret;
262
263 while (isspace(id[0])) {
264 ++parsed;
265 ++id;
266 }
267
268 assert(id[0] == ']');
269
270 if (id[1] == '[') {
271 *has_predicate = 1;
272 }
273
274 return parsed+1;
275}
276
277/**
278 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
279 * the ".." and the first node-identifier, other calls parse a single
280 * node-identifier each.
281 *
282 * path-key-expr = current-function-invocation *WSP "/" *WSP
283 * rel-path-keyexpr
284 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
285 * *(node-identifier *WSP "/" *WSP)
286 * node-identifier
287 *
Michal Vaskobb211122015-08-19 14:03:11 +0200288 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200289 * @param[out] prefix Points to the prefix, NULL if there is not any.
290 * @param[out] pref_len Length of the prefix, 0 if there is not any.
291 * @param[out] name Points to the node name.
292 * @param[out] nam_len Length of the node name.
293 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
294 * must not be changed between consecutive calls.
295 * @return Number of characters successfully parsed,
296 * positive on success, negative on failure.
297 */
298static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200299parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
300 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200301{
302 int parsed = 0, ret, par_times = 0;
303
304 assert(id);
305 assert(parent_times);
306 if (prefix) {
307 *prefix = NULL;
308 }
309 if (pref_len) {
310 *pref_len = 0;
311 }
312 if (name) {
313 *name = NULL;
314 }
315 if (nam_len) {
316 *nam_len = 0;
317 }
318
319 if (!*parent_times) {
320 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
321 if (strncmp(id, "current()", 9)) {
322 return -parsed;
323 }
324
325 parsed += 9;
326 id += 9;
327
328 while (isspace(id[0])) {
329 ++parsed;
330 ++id;
331 }
332
333 if (id[0] != '/') {
334 return -parsed;
335 }
336
337 ++parsed;
338 ++id;
339
340 while (isspace(id[0])) {
341 ++parsed;
342 ++id;
343 }
344
345 /* rel-path-keyexpr */
346 if (strncmp(id, "..", 2)) {
347 return -parsed;
348 }
349 ++par_times;
350
351 parsed += 2;
352 id += 2;
353
354 while (isspace(id[0])) {
355 ++parsed;
356 ++id;
357 }
358 }
359
360 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
361 *
362 * first parent reference with whitespaces already parsed
363 */
364 if (id[0] != '/') {
365 return -parsed;
366 }
367
368 ++parsed;
369 ++id;
370
371 while (isspace(id[0])) {
372 ++parsed;
373 ++id;
374 }
375
376 while (!strncmp(id, "..", 2) && !*parent_times) {
377 ++par_times;
378
379 parsed += 2;
380 id += 2;
381
382 while (isspace(id[0])) {
383 ++parsed;
384 ++id;
385 }
386
387 if (id[0] != '/') {
388 return -parsed;
389 }
390
391 ++parsed;
392 ++id;
393
394 while (isspace(id[0])) {
395 ++parsed;
396 ++id;
397 }
398 }
399
400 if (!*parent_times) {
401 *parent_times = par_times;
402 }
403
404 /* all parent references must be parsed at this point */
405 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
406 return -parsed+ret;
407 }
408
409 parsed += ret;
410 id += ret;
411
412 return parsed;
413}
414
415/**
416 * @brief Parse path-arg (leafref).
417 *
418 * path-arg = absolute-path / relative-path
419 * absolute-path = 1*("/" (node-identifier *path-predicate))
420 * relative-path = 1*(".." "/") descendant-path
421 *
Michal Vaskobb211122015-08-19 14:03:11 +0200422 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200423 * @param[out] prefix Points to the prefix, NULL if there is not any.
424 * @param[out] pref_len Length of the prefix, 0 if there is not any.
425 * @param[out] name Points to the node name.
426 * @param[out] nam_len Length of the node name.
427 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
428 * must not be changed between consecutive calls. -1 if the
429 * path is relative.
430 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
431 *
432 * @return Number of characters successfully parsed,
433 * positive on success, negative on failure.
434 */
435static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200436parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
437 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200438{
439 int parsed = 0, ret, par_times = 0;
440
441 assert(id);
442 assert(parent_times);
443 if (prefix) {
444 *prefix = NULL;
445 }
446 if (pref_len) {
447 *pref_len = 0;
448 }
449 if (name) {
450 *name = NULL;
451 }
452 if (nam_len) {
453 *nam_len = 0;
454 }
455 if (has_predicate) {
456 *has_predicate = 0;
457 }
458
459 if (!*parent_times && !strncmp(id, "..", 2)) {
460 ++par_times;
461
462 parsed += 2;
463 id += 2;
464
465 while (!strncmp(id, "/..", 3)) {
466 ++par_times;
467
468 parsed += 3;
469 id += 3;
470 }
471 }
472
473 if (!*parent_times) {
474 if (par_times) {
475 *parent_times = par_times;
476 } else {
477 *parent_times = -1;
478 }
479 }
480
481 if (id[0] != '/') {
482 return -parsed;
483 }
484
485 /* skip '/' */
486 ++parsed;
487 ++id;
488
489 /* node-identifier ([prefix:]identifier) */
490 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
491 return -parsed-ret;
492 }
493
494 parsed += ret;
495 id += ret;
496
497 /* there is no predicate */
498 if ((id[0] == '/') || !id[0]) {
499 return parsed;
500 } else if (id[0] != '[') {
501 return -parsed;
502 }
503
504 if (has_predicate) {
505 *has_predicate = 1;
506 }
507
508 return parsed;
509}
510
511/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200512 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200513 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200514 *
515 * instance-identifier = 1*("/" (node-identifier *predicate))
516 *
Michal Vaskobb211122015-08-19 14:03:11 +0200517 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200518 * @param[out] model Points to the model name.
519 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200520 * @param[out] name Points to the node name.
521 * @param[out] nam_len Length of the node name.
522 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
523 *
524 * @return Number of characters successfully parsed,
525 * positive on success, negative on failure.
526 */
527static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200528parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
529 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200530{
531 int parsed = 0, ret;
532
533 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200534 if (model) {
535 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200536 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200537 if (mod_len) {
538 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200539 }
540 if (name) {
541 *name = NULL;
542 }
543 if (nam_len) {
544 *nam_len = 0;
545 }
546 if (has_predicate) {
547 *has_predicate = 0;
548 }
549
550 if (id[0] != '/') {
551 return -parsed;
552 }
553
554 ++parsed;
555 ++id;
556
Michal Vasko1f2cc332015-08-19 11:18:32 +0200557 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Michal Vaskobea08e92016-05-18 13:28:08 +0200558 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200559 }
560
561 parsed += ret;
562 id += ret;
563
564 if ((id[0] == '[') && has_predicate) {
565 *has_predicate = 1;
566 }
567
568 return parsed;
569}
570
571/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200572 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200573 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574 *
575 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
576 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
577 * ((DQUOTE string DQUOTE) /
578 * (SQUOTE string SQUOTE))
579 * pos = non-negative-integer-value
580 *
Michal Vaskobb211122015-08-19 14:03:11 +0200581 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200582 * @param[out] model Points to the model name.
583 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200584 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
585 * @param[out] nam_len Length of the node name.
586 * @param[out] value Value the node-identifier must have (string from the grammar),
587 * NULL if there is not any.
588 * @param[out] val_len Length of the value, 0 if there is not any.
589 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
590 *
591 * @return Number of characters successfully parsed,
592 * positive on success, negative on failure.
593 */
594static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200595parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
596 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597{
598 const char *ptr;
599 int parsed = 0, ret;
600 char quote;
601
602 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200603 if (model) {
604 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200605 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200606 if (mod_len) {
607 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200608 }
609 if (name) {
610 *name = NULL;
611 }
612 if (nam_len) {
613 *nam_len = 0;
614 }
615 if (value) {
616 *value = NULL;
617 }
618 if (val_len) {
619 *val_len = 0;
620 }
621 if (has_predicate) {
622 *has_predicate = 0;
623 }
624
625 if (id[0] != '[') {
626 return -parsed;
627 }
628
629 ++parsed;
630 ++id;
631
632 while (isspace(id[0])) {
633 ++parsed;
634 ++id;
635 }
636
637 /* pos */
638 if (isdigit(id[0])) {
639 if (name) {
640 *name = id;
641 }
642
643 if (id[0] == '0') {
644 ++parsed;
645 ++id;
646
647 if (isdigit(id[0])) {
648 return -parsed;
649 }
650 }
651
652 while (isdigit(id[0])) {
653 ++parsed;
654 ++id;
655 }
656
657 if (nam_len) {
658 *nam_len = id-(*name);
659 }
660
661 /* "." */
662 } else if (id[0] == '.') {
663 if (name) {
664 *name = id;
665 }
666 if (nam_len) {
667 *nam_len = 1;
668 }
669
670 ++parsed;
671 ++id;
672
673 /* node-identifier */
674 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200675 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200677 } else if (model && !*model) {
678 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200679 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680
681 parsed += ret;
682 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 }
684
685 while (isspace(id[0])) {
686 ++parsed;
687 ++id;
688 }
689
690 if (id[0] != '=') {
691 return -parsed;
692 }
693
694 ++parsed;
695 ++id;
696
697 while (isspace(id[0])) {
698 ++parsed;
699 ++id;
700 }
701
702 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
703 if ((id[0] == '\"') || (id[0] == '\'')) {
704 quote = id[0];
705
706 ++parsed;
707 ++id;
708
709 if ((ptr = strchr(id, quote)) == NULL) {
710 return -parsed;
711 }
712 ret = ptr-id;
713
714 if (value) {
715 *value = id;
716 }
717 if (val_len) {
718 *val_len = ret;
719 }
720
721 parsed += ret+1;
722 id += ret+1;
723 } else {
724 return -parsed;
725 }
726
727 while (isspace(id[0])) {
728 ++parsed;
729 ++id;
730 }
731
732 if (id[0] != ']') {
733 return -parsed;
734 }
735
736 ++parsed;
737 ++id;
738
739 if ((id[0] == '[') && has_predicate) {
740 *has_predicate = 1;
741 }
742
743 return parsed;
744}
745
746/**
747 * @brief Parse schema-nodeid.
748 *
749 * schema-nodeid = absolute-schema-nodeid /
750 * descendant-schema-nodeid
751 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200752 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200753 * node-identifier
754 * absolute-schema-nodeid
755 *
Michal Vaskobb211122015-08-19 14:03:11 +0200756 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200757 * @param[out] mod_name Points to the module name, NULL if there is not any.
758 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200759 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] nam_len Length of the node name.
761 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
762 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100763 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
764 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 *
766 * @return Number of characters successfully parsed,
767 * positive on success, negative on failure.
768 */
Michal Vasko22448d32016-03-16 13:17:29 +0100769int
Michal Vasko723e50c2015-10-20 15:20:29 +0200770parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100771 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200772{
773 int parsed = 0, ret;
774
775 assert(id);
776 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200777 if (mod_name) {
778 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200779 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200780 if (mod_name_len) {
781 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
783 if (name) {
784 *name = NULL;
785 }
786 if (nam_len) {
787 *nam_len = 0;
788 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100789 if (has_predicate) {
790 *has_predicate = 0;
791 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200792
793 if (id[0] != '/') {
794 if (*is_relative != -1) {
795 return -parsed;
796 } else {
797 *is_relative = 1;
798 }
Michal Vasko48935352016-03-29 11:52:36 +0200799 if (!strncmp(id, "./", 2)) {
800 parsed += 2;
801 id += 2;
802 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200803 } else {
804 if (*is_relative == -1) {
805 *is_relative = 0;
806 }
807 ++parsed;
808 ++id;
809 }
810
Michal Vasko723e50c2015-10-20 15:20:29 +0200811 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200812 return -parsed+ret;
813 }
814
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100815 parsed += ret;
816 id += ret;
817
818 if ((id[0] == '[') && has_predicate) {
819 *has_predicate = 1;
820 }
821
822 return parsed;
823}
824
825/**
826 * @brief Parse schema predicate (special format internally used).
827 *
828 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200829 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100830 * key-with-value = identifier *WSP "=" *WSP
831 * ((DQUOTE string DQUOTE) /
832 * (SQUOTE string SQUOTE))
833 *
834 * @param[in] id Identifier to use.
835 * @param[out] name Points to the list key name.
836 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100837 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100838 * @param[out] val_len Length of \p value.
839 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
840 */
Michal Vasko22448d32016-03-16 13:17:29 +0100841int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200842parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100843 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100844{
845 const char *ptr;
846 int parsed = 0, ret;
847 char quote;
848
849 assert(id);
850 if (name) {
851 *name = NULL;
852 }
853 if (nam_len) {
854 *nam_len = 0;
855 }
856 if (value) {
857 *value = NULL;
858 }
859 if (val_len) {
860 *val_len = 0;
861 }
862 if (has_predicate) {
863 *has_predicate = 0;
864 }
865
866 if (id[0] != '[') {
867 return -parsed;
868 }
869
870 ++parsed;
871 ++id;
872
873 while (isspace(id[0])) {
874 ++parsed;
875 ++id;
876 }
877
Michal Vasko22448d32016-03-16 13:17:29 +0100878 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200879 if (id[0] == '.') {
880 ret = 1;
881 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100882 return -parsed + ret;
883 }
884 if (name) {
885 *name = id;
886 }
887 if (nam_len) {
888 *nam_len = ret;
889 }
890
891 parsed += ret;
892 id += ret;
893
894 while (isspace(id[0])) {
895 ++parsed;
896 ++id;
897 }
898
899 /* there is value as well */
900 if (id[0] == '=') {
901 ++parsed;
902 ++id;
903
904 while (isspace(id[0])) {
905 ++parsed;
906 ++id;
907 }
908
909 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
910 if ((id[0] == '\"') || (id[0] == '\'')) {
911 quote = id[0];
912
913 ++parsed;
914 ++id;
915
916 if ((ptr = strchr(id, quote)) == NULL) {
917 return -parsed;
918 }
919 ret = ptr - id;
920
921 if (value) {
922 *value = id;
923 }
924 if (val_len) {
925 *val_len = ret;
926 }
927
928 parsed += ret + 1;
929 id += ret + 1;
930 } else {
931 return -parsed;
932 }
933
934 while (isspace(id[0])) {
935 ++parsed;
936 ++id;
937 }
Michal Vasko22448d32016-03-16 13:17:29 +0100938 } else if (value) {
939 /* if value was expected, it's mandatory */
940 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100941 }
942
943 if (id[0] != ']') {
944 return -parsed;
945 }
946
947 ++parsed;
948 ++id;
949
950 if ((id[0] == '[') && has_predicate) {
951 *has_predicate = 1;
952 }
953
954 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200955}
956
957/**
Michal 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,
Radek Krejcif3c71de2016-04-11 12:45:46 +0200995 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
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;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001003 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001004 /* shorthand case */
1005 if (!shorthand) {
1006 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001007 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001008 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 Krejcif3c71de2016-04-11 12:45:46 +02001020 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1021 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001022 || !schema) {
1023 result = NULL;
1024 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001025 }
1026 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001027 LY_TREE_FOR(result ? result->child : start, iter) {
1028 if (iter->schema == schema) {
1029 /* move in data tree according to returned schema */
1030 result = iter;
1031 break;
1032 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001033 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001034 if (!iter) {
1035 /* instance not found */
1036 result = NULL;
1037 break;
1038 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001039 }
1040 free(str);
1041
1042 return result;
1043}
1044
Radek Krejcibdf92362016-04-08 14:43:34 +02001045/*
1046 * 0 - ok (done)
1047 * 1 - continue
1048 * 2 - break
1049 * -1 - error
1050 */
1051static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001052schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001053 const struct lys_module *module, const char *mod_name, int mod_name_len,
1054 const struct lys_node **start)
1055{
1056 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001057 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001058
1059 /* module check */
1060 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1061 if (!prefix_mod) {
1062 return -1;
1063 }
1064 if (prefix_mod != lys_node_module(sibling)) {
1065 return 1;
1066 }
1067
1068 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001069 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001070 if (*shorthand != -1) {
1071 *shorthand = *shorthand ? 0 : 1;
1072 }
1073 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001074 }
1075
1076 /* the result node? */
1077 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001078 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001079 return 1;
1080 }
1081 return 0;
1082 }
1083
Radek Krejcicc217a62016-04-08 16:58:11 +02001084 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001085 /* move down the tree, if possible */
1086 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1087 return -1;
1088 }
1089 *start = sibling->child;
1090 }
1091
1092 return 2;
1093}
1094
Michal Vasko3edeaf72016-02-11 13:17:43 +01001095/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1096int
1097resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1098 const struct lys_node **ret)
1099{
1100 const char *name, *mod_name, *id;
1101 const struct lys_node *sibling;
1102 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001103 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001104 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001105 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001106
1107 assert(nodeid && (start || module) && !(start && module) && ret);
1108
1109 id = nodeid;
1110
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001111 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 +01001112 return ((id - nodeid) - r) + 1;
1113 }
1114 id += r;
1115
1116 if ((is_relative && !start) || (!is_relative && !module)) {
1117 return -1;
1118 }
1119
1120 /* descendant-schema-nodeid */
1121 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001122 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001123
1124 /* absolute-schema-nodeid */
1125 } else {
1126 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001127 if (!start_mod) {
1128 return -1;
1129 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001130 start = start_mod->data;
1131 }
1132
1133 while (1) {
1134 sibling = NULL;
1135 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1136 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1137 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001138 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001139 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1140 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001141 *ret = sibling;
1142 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001143 } else if (r == 1) {
1144 continue;
1145 } else if (r == 2) {
1146 break;
1147 } else {
1148 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001149 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001150 }
1151 }
1152
1153 /* no match */
1154 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001155 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001156 return EXIT_SUCCESS;
1157 }
1158
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001159 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 +01001160 return ((id - nodeid) - r) + 1;
1161 }
1162 id += r;
1163 }
1164
1165 /* cannot get here */
1166 LOGINT;
1167 return -1;
1168}
1169
Radek Krejcif3c71de2016-04-11 12:45:46 +02001170/* unique, refine,
1171 * >0 - unexpected char on position (ret - 1),
1172 * 0 - ok (but ret can still be NULL),
1173 * -1 - error,
1174 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001175int
1176resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001177 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001178{
1179 const char *name, *mod_name, *id;
1180 const struct lys_node *sibling;
1181 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001182 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001183 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001184 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001185
1186 assert(nodeid && start && ret);
1187 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1188
1189 id = nodeid;
1190 module = start->module;
1191
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001192 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 +01001193 return ((id - nodeid) - r) + 1;
1194 }
1195 id += r;
1196
1197 if (!is_relative) {
1198 return -1;
1199 }
1200
1201 while (1) {
1202 sibling = NULL;
1203 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1204 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1205 /* name match */
1206 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001207 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1208 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001209 if (!(sibling->nodetype & ret_nodetype)) {
1210 /* wrong node type, too bad */
1211 continue;
1212 }
1213 *ret = sibling;
1214 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001215 } else if (r == 1) {
1216 continue;
1217 } else if (r == 2) {
1218 break;
1219 } else {
1220 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001221 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001222 }
1223 }
1224
1225 /* no match */
1226 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001227 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001228 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001229 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1230 *ret = NULL;
1231 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001232 }
1233
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001234 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 +01001235 return ((id - nodeid) - r) + 1;
1236 }
1237 id += r;
1238 }
1239
1240 /* cannot get here */
1241 LOGINT;
1242 return -1;
1243}
1244
1245/* choice default */
1246int
1247resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1248{
1249 /* cannot actually be a path */
1250 if (strchr(nodeid, '/')) {
1251 return -1;
1252 }
1253
Radek Krejcif3c71de2016-04-11 12:45:46 +02001254 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001255}
1256
1257/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1258static int
1259resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1260{
1261 const struct lys_module *module;
1262 const char *mod_prefix, *name;
1263 int i, mod_prefix_len, nam_len;
1264
1265 /* parse the identifier, it must be parsed on one call */
1266 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1267 return -i + 1;
1268 }
1269
1270 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1271 if (!module) {
1272 return -1;
1273 }
1274 if (module != start->module) {
1275 start = module->data;
1276 }
1277
1278 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1279
1280 return EXIT_SUCCESS;
1281}
1282
1283int
1284resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1285 const struct lys_node **ret)
1286{
1287 const char *name, *mod_name, *id;
1288 const struct lys_node *sibling, *start;
1289 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001290 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001291 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001292
1293 assert(nodeid && module && ret);
1294 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1295
1296 id = nodeid;
1297 start = module->data;
1298
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001299 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 +01001300 return ((id - nodeid) - r) + 1;
1301 }
1302 id += r;
1303
1304 if (is_relative) {
1305 return -1;
1306 }
1307
1308 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001309 if (!abs_start_mod) {
1310 return -1;
1311 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001312
1313 while (1) {
1314 sibling = NULL;
1315 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1316 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1317 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001318 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001319 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1320 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001321 if (!(sibling->nodetype & ret_nodetype)) {
1322 /* wrong node type, too bad */
1323 continue;
1324 }
1325 *ret = sibling;
1326 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001327 } else if (r == 1) {
1328 continue;
1329 } else if (r == 2) {
1330 break;
1331 } else {
1332 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001333 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001334 }
1335 }
1336
1337 /* no match */
1338 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001339 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001340 return EXIT_SUCCESS;
1341 }
1342
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001343 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001344 return ((id - nodeid) - r) + 1;
1345 }
1346 id += r;
1347 }
1348
1349 /* cannot get here */
1350 LOGINT;
1351 return -1;
1352}
1353
Michal Vaskoe733d682016-03-14 09:08:27 +01001354static int
Michal Vasko3547c532016-03-14 09:40:50 +01001355resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001356{
1357 const char *name;
1358 int nam_len, has_predicate, i;
1359
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001360 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1361 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001362 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001363 return -1;
1364 }
1365
1366 predicate += i;
1367 *parsed += i;
1368
1369 for (i = 0; i < list->keys_size; ++i) {
1370 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1371 break;
1372 }
1373 }
1374
1375 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001376 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001377 return -1;
1378 }
1379
1380 /* more predicates? */
1381 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001382 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001383 }
1384
1385 return 0;
1386}
1387
Michal Vasko9fd98e22016-04-07 15:44:19 +02001388/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly
1389 * data_nodeid - 0 schema nodeid, 1 - data nodeid with RPC input, 2 - data nodeid with RPC output */
Michal Vaskoe733d682016-03-14 09:08:27 +01001390const struct lys_node *
Michal Vasko9fd98e22016-04-07 15:44:19 +02001391resolve_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 +01001392{
Michal Vasko10728b52016-04-07 14:26:29 +02001393 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001394 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001395 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001396 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001397 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001398 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001399
Michal Vasko3547c532016-03-14 09:40:50 +01001400 assert(nodeid && (ctx || start));
1401 if (!ctx) {
1402 ctx = start->module->ctx;
1403 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001404
1405 id = nodeid;
1406
Michal Vaskoe733d682016-03-14 09:08:27 +01001407 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 +01001408 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001409 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001410 }
1411 id += r;
1412
1413 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001414 assert(start);
1415 start = start->child;
1416 if (!start) {
1417 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001418 str = strndup(nodeid, (name + nam_len) - nodeid);
1419 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1420 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001421 return NULL;
1422 }
1423 module = start->module;
1424 } else {
1425 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001426 str = strndup(nodeid, (name + nam_len) - nodeid);
1427 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1428 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001429 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001430 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1431 LOGINT;
1432 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001433 }
1434
Michal Vasko971a3ca2016-04-01 13:09:29 +02001435 if (ly_buf_used && module_name[0]) {
1436 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1437 }
1438 ly_buf_used++;
1439
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001440 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001441 module_name[mod_name_len] = '\0';
1442 module = ly_ctx_get_module(ctx, module_name, NULL);
1443
1444 if (buf_backup) {
1445 /* return previous internal buffer content */
1446 strcpy(module_name, buf_backup);
1447 free(buf_backup);
1448 buf_backup = NULL;
1449 }
1450 ly_buf_used--;
1451
Michal Vasko3547c532016-03-14 09:40:50 +01001452 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001453 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1454 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1455 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001456 return NULL;
1457 }
1458 start = module->data;
1459
1460 /* now it's as if there was no module name */
1461 mod_name = NULL;
1462 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001463 }
1464
Michal Vaskoe733d682016-03-14 09:08:27 +01001465 prev_mod = module;
1466
Michal Vasko3edeaf72016-02-11 13:17:43 +01001467 while (1) {
1468 sibling = NULL;
Michal Vasko9fd98e22016-04-07 15:44:19 +02001469 while ((sibling = lys_getnext(sibling, lys_parent(start), module, (data_nodeid ?
1470 0 : LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT)))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001471 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001472 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001473
1474 /* data RPC input/output check */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001475 if ((data_nodeid == 1) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_OUTPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001476 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001477 } else if ((data_nodeid == 2) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_INPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001478 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;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001522 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1523 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
1524 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1525 return NULL;
1526 }
1527 } else if (sibling->nodetype == LYS_LIST) {
1528 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
1529 return NULL;
1530 }
1531 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01001532 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001533 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01001534 }
1535 id += r;
1536 }
1537
Radek Krejcibdf92362016-04-08 14:43:34 +02001538 /* check for shorthand cases - then 'start' does not change */
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001539 if (!data_nodeid && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001540 shorthand = ~shorthand;
1541 }
1542
Michal Vasko3edeaf72016-02-11 13:17:43 +01001543 /* the result node? */
1544 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001545 if (shorthand) {
1546 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02001547 str = strndup(nodeid, (name + nam_len) - nodeid);
1548 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001549 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02001550 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02001551 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02001552 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001553 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001554 }
1555
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001556 if (data_nodeid || !shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001557 /* move down the tree, if possible */
1558 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001559 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01001560 return NULL;
1561 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001562 start = sibling->child;
1563 }
1564
1565 /* update prev mod */
1566 prev_mod = start->module;
1567 break;
1568 }
1569 }
1570
1571 /* no match */
1572 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02001573 str = strndup(nodeid, (name + nam_len) - nodeid);
1574 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1575 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001576 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001577 }
1578
Michal Vaskoe733d682016-03-14 09:08:27 +01001579 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 +01001580 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001581 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001582 }
1583 id += r;
1584 }
1585
1586 /* cannot get here */
1587 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001588 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001589}
1590
Michal Vasko22448d32016-03-16 13:17:29 +01001591static int
1592resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
1593{
1594 const char *name, *value;
1595 int nam_len, val_len, has_predicate = 1, r;
1596 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02001597 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01001598
Radek Krejci61a86c62016-03-24 11:06:44 +01001599 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01001600 assert(node->schema->nodetype == LYS_LIST);
1601
Michal Vaskof29903d2016-04-18 13:13:10 +02001602 key = (struct lyd_node_leaf_list *)node->child;
1603 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
1604 if (!key) {
1605 /* invalid data */
1606 LOGINT;
1607 return -1;
1608 }
Michal Vasko22448d32016-03-16 13:17:29 +01001609
Michal Vasko22448d32016-03-16 13:17:29 +01001610 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001611 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02001612 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001613 }
1614
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001615 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
1616 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001617 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02001618 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001619 }
1620
1621 predicate += r;
1622 *parsed += r;
1623
Michal Vaskof29903d2016-04-18 13:13:10 +02001624 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001625 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02001626 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001627 }
1628
1629 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02001630 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01001631 return 1;
1632 }
Michal Vaskof29903d2016-04-18 13:13:10 +02001633
1634 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01001635 }
1636
1637 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001638 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01001639 return -1;
1640 }
1641
1642 return 0;
1643}
1644
1645struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001646resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
1647 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01001648{
Michal Vasko10728b52016-04-07 14:26:29 +02001649 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01001650 const char *id, *mod_name, *name;
1651 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001652 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001653 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01001654 const struct lys_module *prefix_mod, *prev_mod;
1655 struct ly_ctx *ctx;
1656
1657 assert(nodeid && start && parsed);
1658
1659 ctx = start->schema->module->ctx;
1660 id = nodeid;
1661
1662 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 +01001663 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001664 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001665 return NULL;
1666 }
1667 id += r;
1668 /* add it to parsed only after the data node was actually found */
1669 last_parsed = r;
1670
1671 if (is_relative) {
1672 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01001673 start = start->child;
1674 } else {
1675 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01001676 prev_mod = start->schema->module;
1677 }
1678
1679 while (1) {
1680 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01001681 /* RPC data check, return simply invalid argument, because the data tree is invalid */
1682 if (lys_parent(sibling->schema)) {
1683 if (options & LYD_PATH_OPT_OUTPUT) {
1684 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02001685 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01001686 *parsed = -1;
1687 return NULL;
1688 }
1689 } else {
1690 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02001691 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01001692 *parsed = -1;
1693 return NULL;
1694 }
1695 }
1696 }
1697
Michal Vasko22448d32016-03-16 13:17:29 +01001698 /* name match */
1699 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
1700
1701 /* module check */
1702 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001703 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01001704 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001705 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001706 return NULL;
1707 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001708
1709 if (ly_buf_used && module_name[0]) {
1710 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1711 }
1712 ly_buf_used++;
1713
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001714 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01001715 module_name[mod_name_len] = '\0';
1716 /* will also find an augment module */
1717 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001718
1719 if (buf_backup) {
1720 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001721 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001722 free(buf_backup);
1723 buf_backup = NULL;
1724 }
1725 ly_buf_used--;
1726
Michal Vasko22448d32016-03-16 13:17:29 +01001727 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001728 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1729 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1730 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001731 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001732 return NULL;
1733 }
1734 } else {
1735 prefix_mod = prev_mod;
1736 }
1737 if (prefix_mod != lys_node_module(sibling->schema)) {
1738 continue;
1739 }
1740
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001741 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01001742 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001743 llist = (struct lyd_node_leaf_list *)sibling;
1744 if ((!llist_value && llist->value_str && llist->value_str[0])
1745 || (llist_value && strcmp(llist_value, llist->value_str))) {
1746 continue;
1747 }
Michal Vasko22448d32016-03-16 13:17:29 +01001748 }
1749
Michal Vasko13eb4ac2016-04-06 12:19:37 +02001750 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01001751 if (sibling->schema->nodetype == LYS_LIST) {
1752 r = 0;
1753 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001754 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001755 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001756 return NULL;
1757 }
1758 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
1759 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01001760 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001761 return NULL;
1762 } else if (ret == 1) {
1763 /* this list instance does not match */
1764 continue;
1765 }
1766 id += r;
1767 last_parsed += r;
1768 }
1769
1770 *parsed += last_parsed;
1771
1772 /* the result node? */
1773 if (!id[0]) {
1774 return sibling;
1775 }
1776
1777 /* move down the tree, if possible */
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02001778 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001779 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001780 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001781 return NULL;
1782 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02001783 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01001784 start = sibling->child;
1785 if (start) {
1786 prev_mod = start->schema->module;
1787 }
1788 break;
1789 }
1790 }
1791
1792 /* no match, return last match */
1793 if (!sibling) {
1794 return last_match;
1795 }
1796
1797 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 +01001798 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001799 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001800 return NULL;
1801 }
1802 id += r;
1803 last_parsed = r;
1804 }
1805
1806 /* cannot get here */
1807 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001808 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001809 return NULL;
1810}
1811
Michal Vasko3edeaf72016-02-11 13:17:43 +01001812/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001813 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02001814 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001815 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02001816 * @param[in] str_restr Restriction as a string.
1817 * @param[in] type Type of the restriction.
1818 * @param[out] ret Final interval structure that starts with
1819 * the interval of the initial type, continues with intervals
1820 * of any superior types derived from the initial one, and
1821 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001822 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001823 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001824 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001825int
Michal Vaskoaeb51802016-04-11 10:58:47 +02001826resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001827{
1828 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02001829 int kind;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001830 int64_t local_smin, local_smax;
1831 uint64_t local_umin, local_umax;
1832 long double local_fmin, local_fmax;
1833 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02001834 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001835
1836 switch (type->base) {
1837 case LY_TYPE_BINARY:
1838 kind = 0;
1839 local_umin = 0;
1840 local_umax = 18446744073709551615UL;
1841
1842 if (!str_restr && type->info.binary.length) {
1843 str_restr = type->info.binary.length->expr;
1844 }
1845 break;
1846 case LY_TYPE_DEC64:
1847 kind = 2;
1848 local_fmin = -9223372036854775808.0;
1849 local_fmin /= 1 << type->info.dec64.dig;
1850 local_fmax = 9223372036854775807.0;
1851 local_fmax /= 1 << type->info.dec64.dig;
1852
1853 if (!str_restr && type->info.dec64.range) {
1854 str_restr = type->info.dec64.range->expr;
1855 }
1856 break;
1857 case LY_TYPE_INT8:
1858 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001859 local_smin = __INT64_C(-128);
1860 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001861
1862 if (!str_restr && type->info.num.range) {
1863 str_restr = type->info.num.range->expr;
1864 }
1865 break;
1866 case LY_TYPE_INT16:
1867 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001868 local_smin = __INT64_C(-32768);
1869 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001870
1871 if (!str_restr && type->info.num.range) {
1872 str_restr = type->info.num.range->expr;
1873 }
1874 break;
1875 case LY_TYPE_INT32:
1876 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001877 local_smin = __INT64_C(-2147483648);
1878 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001879
1880 if (!str_restr && type->info.num.range) {
1881 str_restr = type->info.num.range->expr;
1882 }
1883 break;
1884 case LY_TYPE_INT64:
1885 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001886 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1887 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001888
1889 if (!str_restr && type->info.num.range) {
1890 str_restr = type->info.num.range->expr;
1891 }
1892 break;
1893 case LY_TYPE_UINT8:
1894 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001895 local_umin = __UINT64_C(0);
1896 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001897
1898 if (!str_restr && type->info.num.range) {
1899 str_restr = type->info.num.range->expr;
1900 }
1901 break;
1902 case LY_TYPE_UINT16:
1903 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001904 local_umin = __UINT64_C(0);
1905 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001906
1907 if (!str_restr && type->info.num.range) {
1908 str_restr = type->info.num.range->expr;
1909 }
1910 break;
1911 case LY_TYPE_UINT32:
1912 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001913 local_umin = __UINT64_C(0);
1914 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001915
1916 if (!str_restr && type->info.num.range) {
1917 str_restr = type->info.num.range->expr;
1918 }
1919 break;
1920 case LY_TYPE_UINT64:
1921 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001922 local_umin = __UINT64_C(0);
1923 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001924
1925 if (!str_restr && type->info.num.range) {
1926 str_restr = type->info.num.range->expr;
1927 }
1928 break;
1929 case LY_TYPE_STRING:
1930 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001931 local_umin = __UINT64_C(0);
1932 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001933
1934 if (!str_restr && type->info.str.length) {
1935 str_restr = type->info.str.length->expr;
1936 }
1937 break;
1938 default:
1939 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001940 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001941 }
1942
1943 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02001944 if (type->der) {
1945 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001946 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001947 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001948 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001949 assert(!intv || (intv->kind == kind));
1950 }
1951
1952 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001953 /* we do not have any restriction, return superior ones */
1954 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001955 return EXIT_SUCCESS;
1956 }
1957
1958 /* adjust local min and max */
1959 if (intv) {
1960 tmp_intv = intv;
1961
1962 if (kind == 0) {
1963 local_umin = tmp_intv->value.uval.min;
1964 } else if (kind == 1) {
1965 local_smin = tmp_intv->value.sval.min;
1966 } else if (kind == 2) {
1967 local_fmin = tmp_intv->value.fval.min;
1968 }
1969
1970 while (tmp_intv->next) {
1971 tmp_intv = tmp_intv->next;
1972 }
1973
1974 if (kind == 0) {
1975 local_umax = tmp_intv->value.uval.max;
1976 } else if (kind == 1) {
1977 local_smax = tmp_intv->value.sval.max;
1978 } else if (kind == 2) {
1979 local_fmax = tmp_intv->value.fval.max;
1980 }
1981 }
1982
1983 /* finally parse our restriction */
1984 seg_ptr = str_restr;
1985 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001986 if (!tmp_local_intv) {
1987 assert(!local_intv);
1988 local_intv = malloc(sizeof *local_intv);
1989 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001990 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02001991 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001992 tmp_local_intv = tmp_local_intv->next;
1993 }
Michal Vasko253035f2015-12-17 16:58:13 +01001994 if (!tmp_local_intv) {
1995 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02001996 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01001997 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001998
1999 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002000 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002001 tmp_local_intv->next = NULL;
2002
2003 /* min */
2004 ptr = seg_ptr;
2005 while (isspace(ptr[0])) {
2006 ++ptr;
2007 }
2008 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2009 if (kind == 0) {
2010 tmp_local_intv->value.uval.min = atoll(ptr);
2011 } else if (kind == 1) {
2012 tmp_local_intv->value.sval.min = atoll(ptr);
2013 } else if (kind == 2) {
2014 tmp_local_intv->value.fval.min = atoll(ptr);
2015 }
2016
2017 if ((ptr[0] == '+') || (ptr[0] == '-')) {
2018 ++ptr;
2019 }
2020 while (isdigit(ptr[0])) {
2021 ++ptr;
2022 }
2023 } else if (!strncmp(ptr, "min", 3)) {
2024 if (kind == 0) {
2025 tmp_local_intv->value.uval.min = local_umin;
2026 } else if (kind == 1) {
2027 tmp_local_intv->value.sval.min = local_smin;
2028 } else if (kind == 2) {
2029 tmp_local_intv->value.fval.min = local_fmin;
2030 }
2031
2032 ptr += 3;
2033 } else if (!strncmp(ptr, "max", 3)) {
2034 if (kind == 0) {
2035 tmp_local_intv->value.uval.min = local_umax;
2036 } else if (kind == 1) {
2037 tmp_local_intv->value.sval.min = local_smax;
2038 } else if (kind == 2) {
2039 tmp_local_intv->value.fval.min = local_fmax;
2040 }
2041
2042 ptr += 3;
2043 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002044 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002045 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002046 }
2047
2048 while (isspace(ptr[0])) {
2049 ptr++;
2050 }
2051
2052 /* no interval or interval */
2053 if ((ptr[0] == '|') || !ptr[0]) {
2054 if (kind == 0) {
2055 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2056 } else if (kind == 1) {
2057 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2058 } else if (kind == 2) {
2059 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2060 }
2061 } else if (!strncmp(ptr, "..", 2)) {
2062 /* skip ".." */
2063 ptr += 2;
2064 while (isspace(ptr[0])) {
2065 ++ptr;
2066 }
2067
2068 /* max */
2069 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2070 if (kind == 0) {
2071 tmp_local_intv->value.uval.max = atoll(ptr);
2072 } else if (kind == 1) {
2073 tmp_local_intv->value.sval.max = atoll(ptr);
2074 } else if (kind == 2) {
2075 tmp_local_intv->value.fval.max = atoll(ptr);
2076 }
2077 } else if (!strncmp(ptr, "max", 3)) {
2078 if (kind == 0) {
2079 tmp_local_intv->value.uval.max = local_umax;
2080 } else if (kind == 1) {
2081 tmp_local_intv->value.sval.max = local_smax;
2082 } else if (kind == 2) {
2083 tmp_local_intv->value.fval.max = local_fmax;
2084 }
2085 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002086 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002087 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002088 }
2089 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002090 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002091 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002092 }
2093
2094 /* next segment (next OR) */
2095 seg_ptr = strchr(seg_ptr, '|');
2096 if (!seg_ptr) {
2097 break;
2098 }
2099 seg_ptr++;
2100 }
2101
2102 /* check local restrictions against superior ones */
2103 if (intv) {
2104 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002105 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002106
2107 while (tmp_local_intv && tmp_intv) {
2108 /* reuse local variables */
2109 if (kind == 0) {
2110 local_umin = tmp_local_intv->value.uval.min;
2111 local_umax = tmp_local_intv->value.uval.max;
2112
2113 /* it must be in this interval */
2114 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2115 /* this interval is covered, next one */
2116 if (local_umax <= tmp_intv->value.uval.max) {
2117 tmp_local_intv = tmp_local_intv->next;
2118 continue;
2119 /* ascending order of restrictions -> fail */
2120 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002121 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002122 }
2123 }
2124 } else if (kind == 1) {
2125 local_smin = tmp_local_intv->value.sval.min;
2126 local_smax = tmp_local_intv->value.sval.max;
2127
2128 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2129 if (local_smax <= tmp_intv->value.sval.max) {
2130 tmp_local_intv = tmp_local_intv->next;
2131 continue;
2132 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002133 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002134 }
2135 }
2136 } else if (kind == 2) {
2137 local_fmin = tmp_local_intv->value.fval.min;
2138 local_fmax = tmp_local_intv->value.fval.max;
2139
2140 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
2141 if (local_fmax <= tmp_intv->value.fval.max) {
2142 tmp_local_intv = tmp_local_intv->next;
2143 continue;
2144 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002145 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002146 }
2147 }
2148 }
2149
2150 tmp_intv = tmp_intv->next;
2151 }
2152
2153 /* some interval left uncovered -> fail */
2154 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002155 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002156 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002157 }
2158
Michal Vaskoaeb51802016-04-11 10:58:47 +02002159 /* append the local intervals to all the intervals of the superior types, return it all */
2160 if (intv) {
2161 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2162 tmp_intv->next = local_intv;
2163 } else {
2164 intv = local_intv;
2165 }
2166 *ret = intv;
2167
2168 return EXIT_SUCCESS;
2169
2170error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002171 while (intv) {
2172 tmp_intv = intv->next;
2173 free(intv);
2174 intv = tmp_intv;
2175 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002176 while (local_intv) {
2177 tmp_local_intv = local_intv->next;
2178 free(local_intv);
2179 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002180 }
2181
Michal Vaskoaeb51802016-04-11 10:58:47 +02002182 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002183}
2184
Michal Vasko730dfdf2015-08-11 14:48:05 +02002185/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002186 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2187 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002188 *
2189 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002190 * @param[in] mod_name Typedef name module name.
2191 * @param[in] module Main module.
2192 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002193 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002194 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002195 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002196 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002197int
Michal Vasko1e62a092015-12-01 12:27:20 +01002198resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2199 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002200{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002201 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002202 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002203 int tpdf_size;
2204
Michal Vasko1dca6882015-10-22 14:29:42 +02002205 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002206 /* no prefix, try built-in types */
2207 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2208 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002209 if (ret) {
2210 *ret = ly_types[i].def;
2211 }
2212 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002213 }
2214 }
2215 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002216 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002217 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002218 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002219 }
2220 }
2221
Michal Vasko1dca6882015-10-22 14:29:42 +02002222 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002223 /* search in local typedefs */
2224 while (parent) {
2225 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002226 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002227 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2228 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002229 break;
2230
Radek Krejci76512572015-08-04 09:47:08 +02002231 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002232 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2233 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002234 break;
2235
Radek Krejci76512572015-08-04 09:47:08 +02002236 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002237 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2238 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002239 break;
2240
Radek Krejci76512572015-08-04 09:47:08 +02002241 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02002242 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
2243 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002244 break;
2245
Radek Krejci76512572015-08-04 09:47:08 +02002246 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002247 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2248 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002249 break;
2250
Radek Krejci76512572015-08-04 09:47:08 +02002251 case LYS_INPUT:
2252 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02002253 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
2254 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002255 break;
2256
2257 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002258 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002259 continue;
2260 }
2261
2262 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002263 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002264 match = &tpdf[i];
2265 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002266 }
2267 }
2268
Michal Vaskodcf98e62016-05-05 17:53:53 +02002269 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002270 }
Radek Krejcic071c542016-01-27 14:57:51 +01002271 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002272 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002273 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002274 if (!module) {
2275 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002276 }
2277 }
2278
2279 /* search in top level typedefs */
2280 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002281 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002282 match = &module->tpdf[i];
2283 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002284 }
2285 }
2286
2287 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002288 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002289 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002290 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002291 match = &module->inc[i].submodule->tpdf[j];
2292 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002293 }
2294 }
2295 }
2296
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002297 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002298
2299check_leafref:
2300 if (ret) {
2301 *ret = match;
2302 }
2303 if (match->type.base == LY_TYPE_LEAFREF) {
2304 while (!match->type.info.lref.path) {
2305 match = match->type.der;
2306 assert(match);
2307 }
2308 if (!match->type.info.lref.target) {
2309 /* lefref not resolved yet, not good enough */
2310 if (ret) {
2311 *ret = NULL;
2312 }
2313 return EXIT_FAILURE;
2314 }
2315 }
2316 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002317}
2318
Michal Vasko1dca6882015-10-22 14:29:42 +02002319/**
2320 * @brief Check the default \p value of the \p type. Logs directly.
2321 *
2322 * @param[in] type Type definition to use.
2323 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002324 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002325 *
2326 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2327 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002328static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002329check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002330{
Michal Vasko1dca6882015-10-22 14:29:42 +02002331 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002332 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002333
2334 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002335 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002336 node.value_str = value;
2337 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002338 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002339 if (!node.schema) {
2340 LOGMEM;
2341 return -1;
2342 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002343 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01002344 if (!node.schema->name) {
2345 LOGMEM;
2346 return -1;
2347 }
Michal Vasko56826402016-03-02 11:11:37 +01002348 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002349 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002350
Radek Krejci37b756f2016-01-18 10:15:03 +01002351 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002352 if (!type->info.lref.target) {
2353 ret = EXIT_FAILURE;
2354 goto finish;
2355 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002356 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002357
2358 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2359 /* it was converted to JSON format before, nothing else sensible we can do */
2360
2361 } else {
Radek Krejci0b7704f2016-03-18 12:16:14 +01002362 ret = lyp_parse_value(&node, NULL, 1);
Michal Vasko1dca6882015-10-22 14:29:42 +02002363 }
2364
2365finish:
2366 if (node.value_type == LY_TYPE_BITS) {
2367 free(node.value.bit);
2368 }
2369 free((char *)node.schema->name);
2370 free(node.schema);
2371
2372 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002373}
2374
Michal Vasko730dfdf2015-08-11 14:48:05 +02002375/**
2376 * @brief Check a key for mandatory attributes. Logs directly.
2377 *
2378 * @param[in] key The key to check.
2379 * @param[in] flags What flags to check.
2380 * @param[in] list The list of all the keys.
2381 * @param[in] index Index of the key in the key list.
2382 * @param[in] name The name of the keys.
2383 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002384 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002385 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002386 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002387static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002388check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002389{
Radek Krejciadb57612016-02-16 13:34:34 +01002390 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002391 char *dup = NULL;
2392 int j;
2393
2394 /* existence */
2395 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002396 if (name[len] != '\0') {
2397 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002398 if (!dup) {
2399 LOGMEM;
2400 return -1;
2401 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002402 dup[len] = '\0';
2403 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002404 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002405 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002406 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002407 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002408 }
2409
2410 /* uniqueness */
2411 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002412 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002413 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002414 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002415 }
2416 }
2417
2418 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002419 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002420 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002421 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002422 }
2423
2424 /* type of the leaf is not built-in empty */
2425 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002426 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002427 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002428 }
2429
2430 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002431 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002432 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002433 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002434 }
2435
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002436 /* key is not placed from augment */
2437 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002438 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
2439 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002440 return -1;
2441 }
2442
Michal Vaskocca47842016-03-17 10:31:07 +01002443 /* key is not when-conditional */
2444 if (key->when) {
Radek Krejci02a04992016-03-17 16:06:37 +01002445 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
2446 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
Radek Krejci581ce772015-11-10 17:22:40 +01002447 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002448 }
2449
Michal Vasko0b85aa82016-03-07 14:37:43 +01002450 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02002451}
Michal Vasko730dfdf2015-08-11 14:48:05 +02002452
2453/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002454 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002455 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002456 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002457 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002458 *
2459 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
2460 */
2461int
Radek Krejci48464ed2016-03-17 15:44:09 +01002462resolve_unique(struct lys_node *parent, const char *uniq_str_path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002463{
Radek Krejci581ce772015-11-10 17:22:40 +01002464 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002465 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002466
Radek Krejcif3c71de2016-04-11 12:45:46 +02002467 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002468 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002469 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002470 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002471 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002472 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02002473 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02002474 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01002475 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002476 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01002477 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01002478 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2479 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002480 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002481 }
Radek Krejci581ce772015-11-10 17:22:40 +01002482 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002483 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002484 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002485 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2486 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002487 rc = -1;
2488 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002489 }
2490
Radek Krejcicf509982015-12-15 09:22:44 +01002491 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01002492 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002493 return -1;
2494 }
2495
Radek Krejcica7efb72016-01-18 13:06:01 +01002496 /* set leaf's unique flag */
2497 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2498
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002499 return EXIT_SUCCESS;
2500
2501error:
2502
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002503 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002504}
2505
Michal Vasko730dfdf2015-08-11 14:48:05 +02002506/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002507 * @brief Resolve (find) a feature definition. Logs directly.
2508 *
2509 * @param[in] name Feature name.
2510 * @param[in] module Module to search in.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002511 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002512 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002513 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002514 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002515static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002516resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002517{
Michal Vasko2d851a92015-10-20 16:16:36 +02002518 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002519 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002520 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002521
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002522 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002523 assert(module);
2524
2525 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002526 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002527 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002528 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002529 }
2530
Radek Krejcic071c542016-01-27 14:57:51 +01002531 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2532 if (!module) {
2533 /* identity refers unknown data model */
Radek Krejci48464ed2016-03-17 15:44:09 +01002534 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002535 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002536 }
2537
Radek Krejcic071c542016-01-27 14:57:51 +01002538 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002539 for (j = 0; j < module->features_size; j++) {
2540 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002541 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002542 /* check status */
2543 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002544 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejci48464ed2016-03-17 15:44:09 +01002545 module->features[j].module, module->features[j].name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002546 return -1;
2547 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002548 *ret = &module->features[j];
2549 }
2550 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002551 }
2552 }
Radek Krejcic071c542016-01-27 14:57:51 +01002553 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002554 for (i = 0; i < module->inc_size; i++) {
2555 if (!module->inc[i].submodule) {
2556 /* not yet resolved */
2557 continue;
2558 }
Radek Krejcic071c542016-01-27 14:57:51 +01002559 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2560 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2561 if (ret) {
2562 /* check status */
2563 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002564 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002565 module->inc[i].submodule->features[j].flags,
2566 module->inc[i].submodule->features[j].module,
Radek Krejci48464ed2016-03-17 15:44:09 +01002567 module->inc[i].submodule->features[j].name, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002568 return -1;
2569 }
2570 *ret = &(module->inc[i].submodule->features[j]);
2571 }
2572 return EXIT_SUCCESS;
2573 }
2574 }
2575 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002576
2577 /* not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01002578 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002579 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002580}
2581
Radek Krejci0c0086a2016-03-24 15:20:28 +01002582void
Michal Vasko23b61ec2015-08-19 11:19:50 +02002583unres_data_del(struct unres_data *unres, uint32_t i)
2584{
2585 /* there are items after the one deleted */
2586 if (i+1 < unres->count) {
2587 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002588 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002589
2590 /* deleting the last item */
2591 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002592 free(unres->node);
2593 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002594 }
2595
2596 /* if there are no items after and it is not the last one, just move the counter */
2597 --unres->count;
2598}
2599
Michal Vasko0491ab32015-08-19 14:28:29 +02002600/**
2601 * @brief Resolve (find) a data node from a specific module. Does not log.
2602 *
2603 * @param[in] mod Module to search in.
2604 * @param[in] name Name of the data node.
2605 * @param[in] nam_len Length of the name.
2606 * @param[in] start Data node to start the search from.
2607 * @param[in,out] parents Resolved nodes. If there are some parents,
2608 * they are replaced (!!) with the resolvents.
2609 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02002610 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02002611 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002612static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002613resolve_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 +02002614{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002615 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002616 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002617 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002618
Michal Vasko23b61ec2015-08-19 11:19:50 +02002619 if (!parents->count) {
2620 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002621 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002622 if (!parents->node) {
2623 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02002624 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002625 }
Michal Vaskocf024702015-10-08 15:01:42 +02002626 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002627 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002628 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002629 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002630 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002631 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002632 continue;
2633 }
2634 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002635 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002636 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2637 && node->schema->name[nam_len] == '\0') {
2638 /* matching target */
2639 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002640 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002641 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002642 flag = 1;
2643 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002644 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002645 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002646 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2647 if (!parents->node) {
2648 return EXIT_FAILURE;
2649 }
Michal Vaskocf024702015-10-08 15:01:42 +02002650 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002651 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002652 }
2653 }
2654 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002655
2656 if (!flag) {
2657 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002658 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002659 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002660 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002661 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002662 }
2663
Michal Vasko0491ab32015-08-19 14:28:29 +02002664 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002665}
2666
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002667/**
2668 * @brief Resolve (find) a data node. Does not log.
2669 *
Radek Krejci581ce772015-11-10 17:22:40 +01002670 * @param[in] mod_name Module name of the data node.
2671 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002672 * @param[in] name Name of the data node.
2673 * @param[in] nam_len Length of the name.
2674 * @param[in] start Data node to start the search from.
2675 * @param[in,out] parents Resolved nodes. If there are some parents,
2676 * they are replaced (!!) with the resolvents.
2677 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002678 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002679 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002680static int
Radek Krejci581ce772015-11-10 17:22:40 +01002681resolve_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 +02002682 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002683{
Michal Vasko1e62a092015-12-01 12:27:20 +01002684 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002685 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002686
Michal Vasko23b61ec2015-08-19 11:19:50 +02002687 assert(start);
2688
Michal Vasko31fc3672015-10-21 12:08:13 +02002689 if (mod_name) {
2690 /* we have mod_name, find appropriate module */
2691 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002692 if (!str) {
2693 LOGMEM;
2694 return -1;
2695 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002696 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2697 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002698 if (!mod) {
2699 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002700 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002701 }
2702 } else {
2703 /* no prefix, module is the same as of current node */
2704 mod = start->schema->module;
2705 }
2706
2707 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002708}
2709
Michal Vasko730dfdf2015-08-11 14:48:05 +02002710/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002711 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01002712 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002713 *
Michal Vaskobb211122015-08-19 14:03:11 +02002714 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002715 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002716 * @param[in,out] node_match Nodes satisfying the restriction
2717 * without the predicate. Nodes not
2718 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002719 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002720 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002721 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002722 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002723static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002724resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01002725 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002726{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002727 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002728 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002729 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002730 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2731 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002732 uint32_t j;
2733
2734 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002735 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002736 if (!source_match.node) {
2737 LOGMEM;
2738 return -1;
2739 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002740 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002741 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002742 if (!dest_match.node) {
2743 LOGMEM;
2744 return -1;
2745 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002746
2747 do {
2748 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2749 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002750 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002751 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002752 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002753 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002754 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002755 pred += i;
2756
Michal Vasko23b61ec2015-08-19 11:19:50 +02002757 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002758 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002759 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002760
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002761 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002762 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002763 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002764 i = 0;
2765 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002766 }
2767
2768 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002769 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002770 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2772 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002773 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002774 rc = -1;
2775 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002776 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002777 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002778 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002779 dest_match.node[0] = dest_match.node[0]->parent;
2780 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002781 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002782 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002783 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 }
2785 }
2786 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002787 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002788 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002789 i = 0;
2790 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002791 }
2792
2793 if (pke_len == pke_parsed) {
2794 break;
2795 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002796 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 +02002797 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002798 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002799 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002800 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002801 }
2802 pke_parsed += i;
2803 }
2804
2805 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002806 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2807 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002808 goto remove_leafref;
2809 }
2810
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002811 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002812 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002813 goto remove_leafref;
2814 }
2815
2816 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002817 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002818 continue;
2819
2820remove_leafref:
2821 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002822 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 }
2824 } while (has_predicate);
2825
Michal Vaskocf024702015-10-08 15:01:42 +02002826 free(source_match.node);
2827 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002828 if (parsed) {
2829 *parsed = parsed_loc;
2830 }
2831 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002832
2833error:
2834
2835 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002836 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002837 }
2838 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002839 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002840 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002841 if (parsed) {
2842 *parsed = -parsed_loc+i;
2843 }
2844 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002845}
2846
Michal Vasko730dfdf2015-08-11 14:48:05 +02002847/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002848 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002849 *
Michal Vaskocf024702015-10-08 15:01:42 +02002850 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002851 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01002852 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002853 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002854 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002855 */
Michal Vasko184521f2015-09-24 13:14:26 +02002856static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002857resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002858{
Radek Krejci71b795b2015-08-10 16:20:39 +02002859 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002861 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002862 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002863
Michal Vaskocf024702015-10-08 15:01:42 +02002864 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002865
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002866 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002867 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002868
2869 /* searching for nodeset */
2870 do {
2871 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002872 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002873 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002874 goto error;
2875 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002876 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002877 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878
Michal Vasko23b61ec2015-08-19 11:19:50 +02002879 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002880 if (parent_times != -1) {
2881 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002882 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002883 if (!ret->node) {
2884 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002885 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002886 goto error;
2887 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002888 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002889 for (i = 0; i < parent_times; ++i) {
2890 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002891 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002892 /* error, too many .. */
Radek Krejci48464ed2016-03-17 15:44:09 +01002893 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002894 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002895 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002896 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002897 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002898 data = ret->node[0] = node->parent;
2899 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002900 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002901 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002902 free(ret->node);
2903 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002904 } else {
2905 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002906 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002907 }
2908 }
2909
2910 /* absolute path */
2911 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002912 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002913 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002914 if (data->prev) {
2915 for (; data->prev->next; data = data->prev);
2916 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 }
2918 }
2919
2920 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002921 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002922 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002923 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002924 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002925 goto error;
2926 }
2927
2928 if (has_predicate) {
2929 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002930 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002931 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2932 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002933 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002934 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 continue;
2936 }
2937
2938 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002939 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002940 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002941 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002942 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02002943 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02002944 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 goto error;
2946 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002947 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002948 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949
Michal Vasko23b61ec2015-08-19 11:19:50 +02002950 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02002951 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002952 goto error;
2953 }
2954 }
2955 } while (path[0] != '\0');
2956
Michal Vaskof02e3742015-08-05 16:27:02 +02002957 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002958
2959error:
2960
Michal Vaskocf024702015-10-08 15:01:42 +02002961 free(ret->node);
2962 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002963 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002964
Michal Vasko0491ab32015-08-19 14:28:29 +02002965 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002966}
2967
Michal Vasko730dfdf2015-08-11 14:48:05 +02002968/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002969 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002970 *
Michal Vaskobb211122015-08-19 14:03:11 +02002971 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002972 * @param[in] context_node Predicate context node (where the predicate is placed).
2973 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02002974 *
Michal Vasko184521f2015-09-24 13:14:26 +02002975 * @return 0 on forward reference, otherwise the number
2976 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002977 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002978 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002979static int
Radek Krejciadb57612016-02-16 13:34:34 +01002980resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01002981 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02002982{
Michal Vasko1e62a092015-12-01 12:27:20 +01002983 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002984 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2985 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 +02002986 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002987
2988 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002989 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002990 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002991 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002992 return -parsed+i;
2993 }
2994 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002995 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002996
Michal Vasko58090902015-08-13 14:04:15 +02002997 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002998 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002999 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003000 }
Radek Krejciadb57612016-02-16 13:34:34 +01003001 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003002 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003003 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003004 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003005 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003006 }
3007
3008 /* destination */
3009 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3010 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003011 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 +02003012 return -parsed;
3013 }
3014 pke_parsed += i;
3015
Radek Krejciadb57612016-02-16 13:34:34 +01003016 /* parent is actually the parent of this leaf, so skip the first ".." */
3017 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003018 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003019 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003020 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003021 }
Michal Vaskodcf98e62016-05-05 17:53:53 +02003022 dst_node = lys_parent(dst_node);
Michal Vasko1f76a282015-08-04 16:16:53 +02003023 }
3024 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003025 if (!dest_pref) {
3026 dest_pref = dst_node->module->name;
3027 }
3028 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003029 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003030 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003031 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003032 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003033 }
3034
3035 if (pke_len == pke_parsed) {
3036 break;
3037 }
3038
3039 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3040 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003041 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003042 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003043 return -parsed;
3044 }
3045 pke_parsed += i;
3046 }
3047
3048 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02003049 if (dst_node->nodetype != LYS_LEAF) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003050 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Radek Krejci48464ed2016-03-17 15:44:09 +01003051 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
3052 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003053 return -parsed;
3054 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003055 } while (has_predicate);
3056
3057 return parsed;
3058}
3059
Michal Vasko730dfdf2015-08-11 14:48:05 +02003060/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003061 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003062 *
Michal Vaskobb211122015-08-19 14:03:11 +02003063 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003064 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003065 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3066 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003067 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003068 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003069 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003070 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003071static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003072resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003073 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003074{
Michal Vasko1e62a092015-12-01 12:27:20 +01003075 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01003076 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02003077 const char *id, *prefix, *name;
3078 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02003079 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003080
Michal Vasko184521f2015-09-24 13:14:26 +02003081 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003082 parent_times = 0;
3083 id = path;
3084
3085 do {
3086 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003087 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 +02003088 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003089 }
3090 id += i;
3091
Michal Vasko184521f2015-09-24 13:14:26 +02003092 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003093 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003094 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003095 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01003096 /* get start node */
3097 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003098 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003099 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3100 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003101 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003102 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003103 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02003104 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01003105 if (parent_tpdf) {
3106 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003107 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003108 return -1;
3109 }
3110
Radek Krejciadb57612016-02-16 13:34:34 +01003111 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02003112 i = 0;
3113 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003114 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003115 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3116 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003117 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003118 }
Michal Vasko58090902015-08-13 14:04:15 +02003119
3120 /* this node is a wrong node, we actually need the augment target */
3121 if (node->nodetype == LYS_AUGMENT) {
3122 node = ((struct lys_node_augment *)node)->target;
3123 if (!node) {
3124 continue;
3125 }
3126 }
3127
3128 ++i;
3129 if (i == parent_times) {
3130 break;
3131 }
Michal Vaskodcf98e62016-05-05 17:53:53 +02003132 node = lys_parent(node);
Michal Vasko1f76a282015-08-04 16:16:53 +02003133 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003134
Michal Vasko1f76a282015-08-04 16:16:53 +02003135 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02003136 } else {
3137 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003138 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003139 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003140
Michal Vasko184521f2015-09-24 13:14:26 +02003141 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003142 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003143 /* move down the tree, if possible */
3144 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003145 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 +01003146 return -1;
3147 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003148 node = node->child;
3149 }
3150
Michal Vasko4f0dad02016-02-15 14:08:23 +01003151 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003152 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003153 }
3154
Michal Vasko36cbaa42015-12-14 13:15:48 +01003155 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 +02003156 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003157 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003158 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003159 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003160
3161 if (has_predicate) {
3162 /* we have predicate, so the current result must be list */
3163 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003164 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003165 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003166 }
3167
Radek Krejci48464ed2016-03-17 15:44:09 +01003168 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003169 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003170 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003171 } else if (i < 0) {
3172 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003173 }
3174 id += i;
3175 }
3176 } while (id[0]);
3177
Radek Krejcib1c12512015-08-11 11:22:04 +02003178 /* the target must be leaf or leaf-list */
3179 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003180 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003181 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003182 }
3183
Radek Krejcicf509982015-12-15 09:22:44 +01003184 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003185 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003186 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003187 return -1;
3188 }
3189
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003190 if (ret) {
3191 *ret = node;
3192 }
3193 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003194}
3195
Michal Vasko730dfdf2015-08-11 14:48:05 +02003196/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003197 * @brief Resolve instance-identifier predicate in JSON data format.
3198 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003199 *
Michal Vaskobb211122015-08-19 14:03:11 +02003200 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003201 * @param[in,out] node_match Nodes matching the restriction without
3202 * the predicate. Nodes not satisfying
3203 * the predicate are removed.
3204 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003205 * @return Number of characters successfully parsed,
3206 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003207 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003209resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003211 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003212 struct unres_data target_match;
3213 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003214 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003215 const char *model, *name, *value;
3216 char *str;
3217 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3218 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003219
Michal Vasko1f2cc332015-08-19 11:18:32 +02003220 assert(pred && node_match->count);
3221
Michal Vaskocf024702015-10-08 15:01:42 +02003222 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003223 idx = -1;
3224 parsed = 0;
3225
3226 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003227 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003228 return -parsed+i;
3229 }
3230 parsed += i;
3231 pred += i;
3232
Michal Vasko1f2cc332015-08-19 11:18:32 +02003233 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234 if (isdigit(name[0])) {
3235 idx = atoi(name);
3236 }
3237
Michal Vasko1f2cc332015-08-19 11:18:32 +02003238 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003239 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003240 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003241 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003242 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003243 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003244 if (!target_match.node) {
3245 LOGMEM;
3246 return -1;
3247 }
Michal Vaskocf024702015-10-08 15:01:42 +02003248 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003249 } else {
3250 str = strndup(model, mod_len);
3251 mod = ly_ctx_get_module(ctx, str, NULL);
3252 free(str);
3253
Radek Krejci804836a2016-02-03 10:39:55 +01003254 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003255 goto remove_instid;
3256 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 }
3258
3259 /* check that we have the correct type */
3260 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003261 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262 goto remove_instid;
3263 }
3264 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003265 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 goto remove_instid;
3267 }
3268 }
3269
Michal Vasko83a6c462015-10-08 16:43:53 +02003270 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3271 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003272 || (!value && (idx != cur_idx))) {
3273 goto remove_instid;
3274 }
3275
Michal Vaskocf024702015-10-08 15:01:42 +02003276 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277
3278 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003279 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003280 continue;
3281
3282remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003283 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284
3285 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003286 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003287 }
3288 } while (has_predicate);
3289
3290 return parsed;
3291}
3292
Michal Vasko730dfdf2015-08-11 14:48:05 +02003293/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003294 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003295 *
Radek Krejciadb57612016-02-16 13:34:34 +01003296 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003297 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003298 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003299 * @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 +02003300 */
Michal Vasko184521f2015-09-24 13:14:26 +02003301static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003302resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303{
Radek Krejcic5090c32015-08-12 09:46:19 +02003304 int i = 0, j;
3305 struct lyd_node *result = NULL;
Michal Vaskobea08e92016-05-18 13:28:08 +02003306 const struct lys_module *mod, *prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003307 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003308 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003309 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003310 int mod_len, name_len, has_predicate;
3311 struct unres_data node_match;
3312 uint32_t k;
3313
3314 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003315
Radek Krejcic5090c32015-08-12 09:46:19 +02003316 /* we need root to resolve absolute path */
3317 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003318 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003319 if (data->prev) {
3320 for (; data->prev->next; data = data->prev);
3321 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003322
Michal Vaskobea08e92016-05-18 13:28:08 +02003323 prev_mod = lyd_node_module(data);
3324
Radek Krejcic5090c32015-08-12 09:46:19 +02003325 /* search for the instance node */
3326 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003327 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003328 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003329 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330 goto error;
3331 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003332 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003333
Michal Vaskobea08e92016-05-18 13:28:08 +02003334 if (model) {
3335 str = strndup(model, mod_len);
3336 if (!str) {
3337 LOGMEM;
3338 goto error;
3339 }
3340 mod = ly_ctx_get_module(ctx, str, NULL);
3341 free(str);
3342 } else {
3343 mod = prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003344 }
3345
Michal Vasko1f2cc332015-08-19 11:18:32 +02003346 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003347 /* no instance exists */
3348 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003349 }
3350
3351 if (has_predicate) {
3352 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003353 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003354 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3355 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3356 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003357 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003358 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003359 continue;
3360 }
3361
3362 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003363 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003365
Michal Vaskof39142b2015-10-21 11:40:05 +02003366 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003367 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003368 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369 goto error;
3370 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003371 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003372
Michal Vasko1f2cc332015-08-19 11:18:32 +02003373 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003374 /* no instance exists */
3375 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003376 }
3377 }
Michal Vaskobea08e92016-05-18 13:28:08 +02003378
3379 prev_mod = mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380 }
3381
Michal Vasko1f2cc332015-08-19 11:18:32 +02003382 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003383 /* no instance exists */
3384 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003385 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003386 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003387 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003388
Michal Vaskod6adbaa2016-04-11 11:01:09 +02003389 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003390 } else {
3391 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003392 result = node_match.node[0];
3393 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003394
3395 return result;
3396 }
3397
3398error:
3399
3400 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003401 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003402
3403 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404}
3405
Michal Vasko730dfdf2015-08-11 14:48:05 +02003406/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003407 * @brief Passes config flag down to children, skips nodes without config flags.
3408 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003409 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003410 * @param[in] node Siblings and their children to have flags changed.
3411 * @param[in] flags Flags to assign to all the nodes.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003412 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003413static void
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003414inherit_config_flag(struct lys_node *node, int flags)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003415{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003416 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02003417 LY_TREE_FOR(node, node) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003418 if (node->flags & LYS_CONFIG_SET) {
3419 /* skip nodes with an explicit config value */
3420 continue;
3421 }
3422 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
3423 node->flags |= flags;
3424 }
3425 inherit_config_flag(node->child, flags);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 }
3427}
3428
Michal Vasko730dfdf2015-08-11 14:48:05 +02003429/**
Michal Vasko7178e692016-02-12 15:58:05 +01003430 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003431 *
Michal Vaskobb211122015-08-19 14:03:11 +02003432 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003433 * @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 +02003434 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003435 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003436 */
Michal Vasko7178e692016-02-12 15:58:05 +01003437static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003438resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003439{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003440 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003441 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003442
Michal Vasko1d87a922015-08-21 12:57:16 +02003443 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003444
3445 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003446 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 +01003447 if (rc == -1) {
3448 return -1;
3449 }
3450 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003451 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003452 return -1;
3453 }
3454 if (!aug->target) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003455 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003456 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003457 }
3458
3459 if (!aug->child) {
3460 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003461 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462 return EXIT_SUCCESS;
3463 }
3464
Michal Vaskod58d5962016-03-02 14:29:41 +01003465 /* check for mandatory nodes - if the target node is in another module
3466 * the added nodes cannot be mandatory
3467 */
3468 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3469 && lyp_check_mandatory((struct lys_node *)aug)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003470 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
3471 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 +01003472 return -1;
3473 }
3474
Michal Vasko07e89ef2016-03-03 13:28:57 +01003475 /* check augment target type and then augment nodes type */
3476 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3477 LY_TREE_FOR(aug->child, sub) {
3478 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003479 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3480 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003481 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3482 return -1;
3483 }
3484 }
3485 } else if (aug->target->nodetype == LYS_CHOICE) {
3486 LY_TREE_FOR(aug->child, sub) {
3487 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003488 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3489 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003490 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3491 return -1;
3492 }
3493 }
3494 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003495 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3496 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003497 return -1;
3498 }
3499
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003500 /* inherit config information from actual parent */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003502 inherit_config_flag(sub, aug->target->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003503 }
3504
Radek Krejcic071c542016-01-27 14:57:51 +01003505 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003506 LY_TREE_FOR(aug->child, sub) {
Michal Vasko2afc1ca2016-05-03 11:38:53 +02003507 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003508 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003509 }
3510 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003511 /* reconnect augmenting data into the target - add them to the target child list */
3512 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003513 sub = aug->target->child->prev; /* remember current target's last node */
3514 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003515 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003516 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003517 } else {
3518 aug->target->child = aug->child;
3519 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520
3521 return EXIT_SUCCESS;
3522}
3523
Michal Vasko730dfdf2015-08-11 14:48:05 +02003524/**
3525 * @brief Resolve uses, apply augments, refines. Logs directly.
3526 *
Michal Vaskobb211122015-08-19 14:03:11 +02003527 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003528 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003529 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003530 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003531 */
Michal Vasko184521f2015-09-24 13:14:26 +02003532static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003533resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534{
3535 struct ly_ctx *ctx;
Radek Krejci989790c2016-04-14 17:49:41 +02003536 struct lys_node *node = NULL, *next, *iter;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003537 struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003538 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003539 struct lys_restr *must, **old_must;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003540 int i, j, rc, parent_flags;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003541 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542
Michal Vasko71e1aa82015-08-12 12:17:51 +02003543 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003544 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003545 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003546
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003547 if (!uses->grp->child) {
3548 /* grouping without children, warning was already displayed */
3549 return EXIT_SUCCESS;
3550 }
3551
3552 /* get proper parent (config) flags */
3553 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
3554 if (node_aux) {
3555 parent_flags = node_aux->flags & LYS_CONFIG_MASK;
3556 } else {
3557 /* default */
3558 parent_flags = LYS_CONFIG_W;
3559 }
3560
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003561 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003562 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003563 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, 0, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003564 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003565 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3566 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003567 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003569 }
3570 ctx = uses->module->ctx;
3571
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003572 if (parent_flags) {
3573 assert(uses->child);
3574 inherit_config_flag(uses->child, parent_flags);
3575 }
3576
Michal Vaskodef0db12015-10-07 13:22:48 +02003577 /* we managed to copy the grouping, the rest must be possible to resolve */
3578
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003579 /* apply refines */
3580 for (i = 0; i < uses->refine_size; i++) {
3581 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003582 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02003583 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003584 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003585 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003586 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587 }
3588
Radek Krejci1d82ef62015-08-07 14:44:40 +02003589 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003590 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3591 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003592 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003593 }
3594
3595 /* description on any nodetype */
3596 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003597 lydict_remove(ctx, node->dsc);
3598 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 }
3600
3601 /* reference on any nodetype */
3602 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003603 lydict_remove(ctx, node->ref);
3604 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003605 }
3606
3607 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003608 if (rfn->flags & LYS_CONFIG_MASK) {
Michal Vaskodcf98e62016-05-05 17:53:53 +02003609 if (lys_parent(node) &&
3610 ((lys_parent(node)->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
Radek Krejci989790c2016-04-14 17:49:41 +02003611 (rfn->flags & LYS_CONFIG_W)) {
3612 /* setting config true under config false is prohibited */
3613 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
3614 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
3615 "changing config from 'false' to 'true' is prohibited while "
3616 "the target's parent is still config 'false'.");
3617 return -1;
3618 }
3619
Radek Krejci1d82ef62015-08-07 14:44:40 +02003620 node->flags &= ~LYS_CONFIG_MASK;
3621 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Radek Krejci989790c2016-04-14 17:49:41 +02003622
3623 /* inherit config change to the target children */
3624 LY_TREE_DFS_BEGIN(node->child, next, iter) {
3625 if (rfn->flags & LYS_CONFIG_W) {
3626 if (iter->flags & LYS_CONFIG_SET) {
3627 /* config is set explicitely, go to next sibling */
3628 next = NULL;
3629 goto nextsibling;
3630 }
3631 } else { /* LYS_CONFIG_R */
3632 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
3633 /* error - we would have config data under status data */
3634 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
3635 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
3636 "changing config from 'true' to 'false' is prohibited while the target "
3637 "has still a children with explicit config 'true'.");
3638 return -1;
3639 }
3640 }
3641 /* change config */
3642 iter->flags &= ~LYS_CONFIG_MASK;
3643 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
3644
3645 /* select next iter - modified LY_TREE_DFS_END */
3646 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
3647 next = NULL;
3648 } else {
3649 next = iter->child;
3650 }
3651nextsibling:
3652 if (!next) {
3653 /* no children */
3654 if (iter == node->child) {
3655 /* we are done, (START) has no children */
3656 break;
3657 }
3658 /* try siblings */
3659 next = iter->next;
3660 }
3661 while (!next) {
3662 /* parent is already processed, go to its sibling */
3663 iter = lys_parent(iter);
3664
3665 /* no siblings, go back through parents */
3666 if (iter == node) {
3667 /* we are done, no next element to process */
3668 break;
3669 }
3670 next = iter->next;
3671 }
3672 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003673 }
3674
3675 /* default value ... */
3676 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003677 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003678 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003679 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3680 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3681 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003683 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3684 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003685 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003686 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003687 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003688 }
3689 }
3690 }
3691
3692 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003693 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003694 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003696 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003697
3698 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003699 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003700 }
3701 }
3702
3703 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003704 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3705 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3706 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003707 }
3708
3709 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003710 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003711 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003712 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003713 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003714 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003715 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003716 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003717 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003718 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003719 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003720 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02003721 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003722 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003723 }
3724 }
3725
3726 /* must in leaf, leaf-list, list, container or anyxml */
3727 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003728 switch (node->nodetype) {
3729 case LYS_LEAF:
3730 old_size = &((struct lys_node_leaf *)node)->must_size;
3731 old_must = &((struct lys_node_leaf *)node)->must;
3732 break;
3733 case LYS_LEAFLIST:
3734 old_size = &((struct lys_node_leaflist *)node)->must_size;
3735 old_must = &((struct lys_node_leaflist *)node)->must;
3736 break;
3737 case LYS_LIST:
3738 old_size = &((struct lys_node_list *)node)->must_size;
3739 old_must = &((struct lys_node_list *)node)->must;
3740 break;
3741 case LYS_CONTAINER:
3742 old_size = &((struct lys_node_container *)node)->must_size;
3743 old_must = &((struct lys_node_container *)node)->must;
3744 break;
3745 case LYS_ANYXML:
3746 old_size = &((struct lys_node_anyxml *)node)->must_size;
3747 old_must = &((struct lys_node_anyxml *)node)->must;
3748 break;
3749 default:
3750 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003751 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003752 }
3753
3754 size = *old_size + rfn->must_size;
3755 must = realloc(*old_must, size * sizeof *rfn->must);
3756 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003757 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003758 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003759 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003760 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3761 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3762 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3763 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3764 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3765 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003766 }
3767
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003768 *old_must = must;
3769 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003770 }
3771 }
3772
3773 /* apply augments */
3774 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003775 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003776 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003777 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003778 }
3779 }
3780
3781 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003782}
3783
Michal Vasko730dfdf2015-08-11 14:48:05 +02003784/**
3785 * @brief Resolve base identity recursively. Does not log.
3786 *
3787 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003788 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003789 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003790 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003791 *
Michal Vaskof2006002016-04-21 16:28:15 +02003792 * @return EXIT_SUCCESS on success (but ret can still be NULL), EXIT_FAILURE on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003793 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003794static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003795resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003796 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003797{
Michal Vaskof02e3742015-08-05 16:27:02 +02003798 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003799 struct lys_ident *base = NULL, *base_iter;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003800
Radek Krejcicf509982015-12-15 09:22:44 +01003801 assert(ret);
3802
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803 /* search module */
3804 for (i = 0; i < module->ident_size; i++) {
3805 if (!strcmp(basename, module->ident[i].name)) {
3806
3807 if (!ident) {
3808 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003809 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003810 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003811 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003812 }
3813
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003814 base = &module->ident[i];
3815 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003816 }
3817 }
3818
3819 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003820 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3821 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3822 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003823
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003824 if (!ident) {
3825 *ret = &module->inc[j].submodule->ident[i];
3826 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003827 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003828
3829 base = &module->inc[j].submodule->ident[i];
3830 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003831 }
3832 }
3833 }
3834
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003835matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003836 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003837 if (base) {
3838 /* check for circular reference */
3839 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3840 if (ident == base_iter) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003841 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
3842 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003843 return EXIT_FAILURE;
3844 }
3845 }
3846 /* checks done, store the result */
3847 ident->base = base;
3848
3849 /* maintain backlinks to the derived identitise */
3850 while (base) {
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003851 /* 1. get current number of backlinks */
3852 if (base->der) {
3853 for (i = 0; base->der[i]; i++);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003854 } else {
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003855 i = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003856 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003857 base->der = ly_realloc(base->der, (i + 2) * sizeof *(base->der));
3858 if (!base->der) {
Michal Vasko253035f2015-12-17 16:58:13 +01003859 LOGMEM;
3860 return EXIT_FAILURE;
3861 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003862 base->der[i] = ident;
3863 base->der[i + 1] = NULL; /* array termination */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003864
Radek Krejcibabbff82016-02-19 13:31:37 +01003865 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003866 }
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003867
Radek Krejcicf509982015-12-15 09:22:44 +01003868 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003869 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003870 }
3871
Michal Vaskof2006002016-04-21 16:28:15 +02003872 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003873}
3874
Michal Vasko730dfdf2015-08-11 14:48:05 +02003875/**
3876 * @brief Resolve base identity. Logs directly.
3877 *
3878 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003879 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003880 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003881 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01003882 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003883 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003884 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003885 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003886static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003887resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejci48464ed2016-03-17 15:44:09 +01003888 struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003889{
3890 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003891 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003892 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02003893 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01003894 struct lys_module *mod;
3895
3896 assert((ident && !type) || (!ident && type));
3897
3898 if (!type) {
3899 /* have ident to resolve */
3900 ret = &target;
3901 flags = ident->flags;
3902 mod = ident->module;
3903 } else {
3904 /* have type to fill */
3905 ret = &type->info.ident.ref;
3906 flags = type->parent->flags;
3907 mod = type->parent->module;
3908 }
Michal Vaskof2006002016-04-21 16:28:15 +02003909 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003910
3911 /* search for the base identity */
3912 name = strchr(basename, ':');
3913 if (name) {
3914 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003915 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003916 name++;
3917
Michal Vasko2d851a92015-10-20 16:16:36 +02003918 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003919 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003920 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003921 }
3922 } else {
3923 name = basename;
3924 }
3925
Radek Krejcic071c542016-01-27 14:57:51 +01003926 /* get module where to search */
3927 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3928 if (!module) {
3929 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01003930 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003931 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003932 }
3933
Radek Krejcic071c542016-01-27 14:57:51 +01003934 /* search in the identified module ... */
Michal Vaskof2006002016-04-21 16:28:15 +02003935 if (resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003936 return EXIT_FAILURE;
Michal Vaskof2006002016-04-21 16:28:15 +02003937 } else if (*ret) {
3938 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003939 }
Radek Krejcic071c542016-01-27 14:57:51 +01003940 /* and all its submodules */
3941 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskof2006002016-04-21 16:28:15 +02003942 if (resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003943 return EXIT_FAILURE;
Michal Vaskof2006002016-04-21 16:28:15 +02003944 } else if (*ret) {
3945 goto success;
Radek Krejcic071c542016-01-27 14:57:51 +01003946 }
3947 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003948
Michal Vaskof2006002016-04-21 16:28:15 +02003949 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003950 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003951
3952success:
3953 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003954 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
3955 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003956 return -1;
3957 }
3958
3959 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003960}
3961
Michal Vasko730dfdf2015-08-11 14:48:05 +02003962/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003963 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003964 *
3965 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003966 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01003967 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003968 *
3969 * @return Pointer to the identity resolvent, NULL on error.
3970 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003971struct lys_ident *
Radek Krejci48464ed2016-03-17 15:44:09 +01003972resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003974 const char *mod_name, *name;
3975 int mod_name_len, rc;
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003976 int i;
3977 struct lys_ident *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003978
Michal Vaskofb0873c2015-08-21 09:00:07 +02003979 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003980 return NULL;
3981 }
3982
Michal Vaskoc633ca02015-08-21 14:03:51 +02003983 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003984 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003985 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003986 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003987 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01003988 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003989 return NULL;
3990 }
3991
Michal Vaskoc633ca02015-08-21 14:03:51 +02003992 if (!strcmp(base->name, name) && (!mod_name
3993 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003994 return base;
3995 }
3996
Radek Krejci1b61d0e2016-04-15 13:55:44 +02003997 if (base->der) {
3998 for (der = base->der[i = 0]; base->der[i]; der = base->der[++i]) {
3999 if (!strcmp(der->name, name) &&
4000 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
4001 /* we have match */
4002 return der;
4003 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004004 }
4005 }
4006
Radek Krejci48464ed2016-03-17 15:44:09 +01004007 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004008 return NULL;
4009}
4010
Michal Vasko730dfdf2015-08-11 14:48:05 +02004011/**
Michal Vasko7955b362015-09-04 14:18:15 +02004012 * @brief Resolve (find) choice default case. Does not log.
4013 *
4014 * @param[in] choic Choice to use.
4015 * @param[in] dflt Name of the default case.
4016 *
4017 * @return Pointer to the default node or NULL.
4018 */
4019static struct lys_node *
4020resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4021{
4022 struct lys_node *child, *ret;
4023
4024 LY_TREE_FOR(choic->child, child) {
4025 if (child->nodetype == LYS_USES) {
4026 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4027 if (ret) {
4028 return ret;
4029 }
4030 }
4031
Radek Krejci749190d2016-02-18 16:26:25 +01004032 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02004033 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
4034 return child;
4035 }
4036 }
4037
4038 return NULL;
4039}
4040
4041/**
Michal Vaskobb211122015-08-19 14:03:11 +02004042 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004043 *
Michal Vaskobb211122015-08-19 14:03:11 +02004044 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004045 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004046 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004047 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004048 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004050resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004052 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01004053 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02004054
Radek Krejci010e54b2016-03-15 09:40:34 +01004055 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
4056 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
4057 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
4058 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
4059 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02004060 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoe91afce2015-08-12 12:21:00 +02004061
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004062 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01004063 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
4064 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004065 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004066 return -1;
4067 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004068 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004069 return -1;
4070 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004071 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004072 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
4073 * (and smaller flags - it uses only a limited set of flags)
4074 */
4075 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004076 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004077 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01004078 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02004079 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004080 }
4081
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004082 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004083 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004084 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004085 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004086 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004087 return EXIT_FAILURE;
4088 }
4089
Radek Krejci48464ed2016-03-17 15:44:09 +01004090 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004091 if (!rc) {
4092 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01004093 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004094 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004095 LOGINT;
4096 return -1;
4097 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02004098 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01004099 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004100 }
Radek Krejcicf509982015-12-15 09:22:44 +01004101
4102 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004103 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01004104 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004105 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004106 return -1;
4107 }
4108
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004109 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004110 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004111 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004112 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004113 }
4114
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004115 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004116}
4117
Michal Vasko730dfdf2015-08-11 14:48:05 +02004118/**
Michal Vasko9957e592015-08-17 15:04:09 +02004119 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004120 *
Michal Vaskobb211122015-08-19 14:03:11 +02004121 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004122 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004123 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004124 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004125 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004126static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004127resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004128{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004129 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01004130 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004131
4132 for (i = 0; i < list->keys_size; ++i) {
4133 /* get the key name */
4134 if ((value = strpbrk(keys_str, " \t\n"))) {
4135 len = value - keys_str;
4136 while (isspace(value[0])) {
4137 value++;
4138 }
4139 } else {
4140 len = strlen(keys_str);
4141 }
4142
Radek Krejcic4283442016-04-22 09:19:27 +02004143 rc = lys_get_sibling(list->child, lys_main_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004144 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02004145 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
4146 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004147 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004148
Radek Krejci48464ed2016-03-17 15:44:09 +01004149 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004150 /* check_key logs */
4151 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004152 }
4153
Radek Krejcicf509982015-12-15 09:22:44 +01004154 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004155 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004156 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
4157 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01004158 return -1;
4159 }
4160
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004161 /* prepare for next iteration */
4162 while (value && isspace(value[0])) {
4163 value++;
4164 }
4165 keys_str = value;
4166 }
4167
Michal Vaskof02e3742015-08-05 16:27:02 +02004168 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004169}
4170
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004171/**
Michal Vaskobf19d252015-10-08 15:39:17 +02004172 * @brief Resolve (check) all must conditions of \p node.
4173 * Logs directly.
4174 *
4175 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02004176 *
4177 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
4178 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004179static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004180resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02004181{
Michal Vaskobf19d252015-10-08 15:39:17 +02004182 uint8_t i, must_size;
4183 struct lys_restr *must;
4184 struct lyxp_set set;
4185
4186 assert(node);
4187 memset(&set, 0, sizeof set);
4188
4189 switch (node->schema->nodetype) {
4190 case LYS_CONTAINER:
4191 must_size = ((struct lys_node_container *)node->schema)->must_size;
4192 must = ((struct lys_node_container *)node->schema)->must;
4193 break;
4194 case LYS_LEAF:
4195 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
4196 must = ((struct lys_node_leaf *)node->schema)->must;
4197 break;
4198 case LYS_LEAFLIST:
4199 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
4200 must = ((struct lys_node_leaflist *)node->schema)->must;
4201 break;
4202 case LYS_LIST:
4203 must_size = ((struct lys_node_list *)node->schema)->must_size;
4204 must = ((struct lys_node_list *)node->schema)->must;
4205 break;
4206 case LYS_ANYXML:
4207 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
4208 must = ((struct lys_node_anyxml *)node->schema)->must;
4209 break;
4210 default:
4211 must_size = 0;
4212 break;
4213 }
4214
4215 for (i = 0; i < must_size; ++i) {
Michal Vasko944a5642016-03-21 11:48:58 +01004216 if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004217 return -1;
4218 }
4219
Michal Vasko944a5642016-03-21 11:48:58 +01004220 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02004221
Michal Vasko8146d4c2016-05-09 15:50:29 +02004222 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02004223 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
4224 if (must[i].emsg) {
4225 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
4226 }
4227 if (must[i].eapptag) {
4228 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
4229 }
Michal Vaskobf19d252015-10-08 15:39:17 +02004230 return 1;
4231 }
4232 }
4233
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004234 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02004235}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004236
Michal Vaskobf19d252015-10-08 15:39:17 +02004237/**
Michal Vaskocf024702015-10-08 15:01:42 +02004238 * @brief Resolve (find) when condition context node. Does not log.
4239 *
4240 * @param[in] node Data node, whose conditional definition is being decided.
4241 * @param[in] schema Schema node with a when condition.
4242 *
4243 * @return Context node.
4244 */
4245static struct lyd_node *
4246resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004247{
Michal Vaskocf024702015-10-08 15:01:42 +02004248 struct lyd_node *parent;
4249 struct lys_node *sparent;
4250 uint16_t i, data_depth, schema_depth;
4251
4252 /* find a not schema-only node */
4253 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
4254 schema = lys_parent(schema);
4255 if (!schema) {
4256 return NULL;
4257 }
4258 }
4259
4260 /* get node depths */
4261 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
4262 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
4263 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
4264 ++schema_depth;
4265 }
4266 }
4267 if (data_depth < schema_depth) {
4268 return NULL;
4269 }
4270
4271 /* find the corresponding data node */
4272 for (i = 0; i < data_depth - schema_depth; ++i) {
4273 node = node->parent;
4274 }
4275 if (node->schema != schema) {
4276 return NULL;
4277 }
4278
4279 return node;
4280}
4281
Radek Krejci03b71f72016-03-16 11:10:09 +01004282int
Radek Krejci01696bf2016-03-18 13:19:36 +01004283resolve_applies_must(const struct lyd_node *node)
4284{
4285 switch (node->schema->nodetype) {
4286 case LYS_CONTAINER:
4287 return ((struct lys_node_container *)node->schema)->must_size;
4288 case LYS_LEAF:
4289 return ((struct lys_node_leaf *)node->schema)->must_size;
4290 case LYS_LEAFLIST:
4291 return ((struct lys_node_leaflist *)node->schema)->must_size;
4292 case LYS_LIST:
4293 return ((struct lys_node_list *)node->schema)->must_size;
4294 case LYS_ANYXML:
4295 return ((struct lys_node_anyxml *)node->schema)->must_size;
4296 default:
4297 return 0;
4298 }
4299}
4300
4301int
Radek Krejci03b71f72016-03-16 11:10:09 +01004302resolve_applies_when(const struct lyd_node *node)
4303{
4304 struct lys_node *parent;
4305
4306 assert(node);
4307
4308 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
4309 return 1;
4310 }
4311
4312 parent = node->schema;
4313 goto check_augment;
4314
4315 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4316 if (((struct lys_node_uses *)parent)->when) {
4317 return 1;
4318 }
4319check_augment:
4320
4321 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
4322 (((struct lys_node_augment *)parent->parent)->when))) {
4323
4324 }
4325 parent = lys_parent(parent);
4326 }
4327
4328 return 0;
4329}
4330
Michal Vaskocf024702015-10-08 15:01:42 +02004331/**
4332 * @brief Resolve (check) all when conditions relevant for \p node.
4333 * Logs directly.
4334 *
4335 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02004336 *
Radek Krejci03b71f72016-03-16 11:10:09 +01004337 * @return
4338 * -1 - error, ly_errno is set
4339 * 0 - true "when" statement
4340 * 0, ly_vecode = LYVE_NOCOND - false "when" statement
4341 * 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 +02004342 */
4343static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004344resolve_when(struct lyd_node *node)
Michal Vaskocf024702015-10-08 15:01:42 +02004345{
4346 struct lyd_node *ctx_node = NULL;
4347 struct lys_node *parent;
4348 struct lyxp_set set;
Radek Krejci51093642016-03-29 10:14:59 +02004349 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02004350
4351 assert(node);
4352 memset(&set, 0, sizeof set);
4353
4354 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko944a5642016-03-21 11:48:58 +01004355 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004356 if (rc) {
4357 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004358 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004359 }
Radek Krejci51093642016-03-29 10:14:59 +02004360 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004361 }
4362
Radek Krejci03b71f72016-03-16 11:10:09 +01004363 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01004364 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02004365 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004366 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004367 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004368 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004369 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004370 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004371 }
Radek Krejci51093642016-03-29 10:14:59 +02004372
4373 /* free xpath set content */
4374 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004375 }
4376
4377 parent = node->schema;
4378 goto check_augment;
4379
4380 /* check when in every schema node that affects node */
4381 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4382 if (((struct lys_node_uses *)parent)->when) {
4383 if (!ctx_node) {
4384 ctx_node = resolve_when_ctx_node(node, parent);
4385 if (!ctx_node) {
4386 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004387 rc = -1;
4388 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004389 }
4390 }
Michal Vasko944a5642016-03-21 11:48:58 +01004391 rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004392 if (rc) {
4393 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004394 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004395 }
Radek Krejci51093642016-03-29 10:14:59 +02004396 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004397 }
4398
Michal Vasko944a5642016-03-21 11:48:58 +01004399 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02004400 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004401 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004402 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004403 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004404 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004405 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004406 }
Radek Krejci51093642016-03-29 10:14:59 +02004407
4408 /* free xpath set content */
4409 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004410 }
4411
4412check_augment:
4413 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
4414 if (!ctx_node) {
4415 ctx_node = resolve_when_ctx_node(node, parent->parent);
4416 if (!ctx_node) {
4417 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004418 rc = -1;
4419 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004420 }
4421 }
Michal Vasko944a5642016-03-21 11:48:58 +01004422 rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004423 if (rc) {
4424 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004425 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004426 }
Radek Krejci51093642016-03-29 10:14:59 +02004427 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004428 }
4429
Michal Vasko944a5642016-03-21 11:48:58 +01004430 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004431
Michal Vasko8146d4c2016-05-09 15:50:29 +02004432 if (!set.val.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004433 ly_vlog_hide(1);
Michal Vasko6ac68282016-04-11 10:56:47 +02004434 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004435 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004436 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004437 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004438 }
Radek Krejci51093642016-03-29 10:14:59 +02004439
4440 /* free xpath set content */
4441 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004442 }
4443
4444 parent = lys_parent(parent);
4445 }
4446
Radek Krejci0b7704f2016-03-18 12:16:14 +01004447 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01004448
Radek Krejci51093642016-03-29 10:14:59 +02004449cleanup:
4450
4451 /* free xpath set content */
4452 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
4453
4454 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004455}
4456
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004457/**
Michal Vaskobb211122015-08-19 14:03:11 +02004458 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004459 *
4460 * @param[in] mod Main module.
4461 * @param[in] item Item to resolve. Type determined by \p type.
4462 * @param[in] type Type of the unresolved item.
4463 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02004464 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004465 *
4466 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4467 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004468static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004469resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01004470 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004471{
Radek Krejci4f78b532016-02-17 13:43:00 +01004472 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02004473 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004474 const char *base_name;
4475
4476 struct lys_ident *ident;
4477 struct lys_type *stype;
4478 struct lys_feature **feat_ptr;
4479 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01004480 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004481 struct yang_type *yang;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004482
4483 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004484 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004485 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004486 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004487 ident = item;
4488
Radek Krejci48464ed2016-03-17 15:44:09 +01004489 rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004490 break;
4491 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004492 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004493 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004494 stype = item;
4495
Radek Krejci48464ed2016-03-17 15:44:09 +01004496 rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004497 break;
4498 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02004499 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004500 stype = item;
4501
Radek Krejci2f12f852016-01-08 12:59:57 +01004502 /* HACK - when there is no parent, we are in top level typedef and in that
4503 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
4504 * know it via tpdf_flag */
4505 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01004506 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01004507 node = (struct lys_node *)stype->parent;
4508 }
4509
Radek Krejci48464ed2016-03-17 15:44:09 +01004510 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01004511 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02004512 if (!tpdf_flag && !rc) {
4513 assert(stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01004514 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02004515 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
4516 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01004517 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01004518 }
4519
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004520 break;
4521 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004522 /* parent */
4523 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004524 stype = item;
4525
Michal Vasko88c29542015-11-27 14:57:53 +01004526 /* HACK type->der is temporarily unparsed type statement */
4527 yin = (struct lyxml_elem *)stype->der;
4528 stype->der = NULL;
4529
Pavol Vicana0e4e672016-02-24 12:20:04 +01004530 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4531 yang = (struct yang_type *)yin;
4532 rc = yang_check_type(mod, node, yang, unres);
4533
4534 if (rc) {
Pavol Vican933aa5a2016-04-09 21:05:46 +02004535 if (rc == -1) {
4536 yang->type->base = yang->base;
4537 lydict_remove(mod->ctx, yang->name);
4538 free(yang);
4539 stype->der = NULL;
4540 } else {
4541 /* may try again later */
4542 stype->der = (struct lys_tpdf *)yang;
4543 }
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004544 } else {
4545 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02004546 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004547 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01004548 }
4549
Michal Vasko88c29542015-11-27 14:57:53 +01004550 } else {
Pavol Vicana0e4e672016-02-24 12:20:04 +01004551 rc = fill_yin_type(mod, node, yin, stype, unres);
4552 if (!rc) {
4553 /* we need to always be able to free this, it's safe only in this case */
4554 lyxml_free(mod->ctx, yin);
4555 } else {
4556 /* may try again later, put all back how it was */
4557 stype->der = (struct lys_tpdf *)yin;
4558 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004559 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004560 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004561 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004562 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004563 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004564 feat_ptr = item;
4565
Radek Krejci48464ed2016-03-17 15:44:09 +01004566 rc = resolve_feature(base_name, mod, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004567 break;
4568 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004569 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004570 break;
4571 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004572 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004573 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004574 stype = item;
4575
Radek Krejci48464ed2016-03-17 15:44:09 +01004576 rc = check_default(stype, base_name, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004577 break;
4578 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004579 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004580 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004581 choic = item;
4582
Michal Vasko7955b362015-09-04 14:18:15 +02004583 choic->dflt = resolve_choice_dflt(choic, base_name);
4584 if (choic->dflt) {
4585 rc = EXIT_SUCCESS;
4586 } else {
4587 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004588 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004589 break;
4590 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004591 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004592 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004593 break;
4594 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004595 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004596 rc = resolve_unique(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004597 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004598 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004599 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01004600 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004601 default:
4602 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 break;
4604 }
4605
Radek Krejci4f78b532016-02-17 13:43:00 +01004606 if (has_str && !rc) {
4607 lydict_remove(mod->ctx, str_snode);
4608 }
4609
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004610 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004611}
4612
Michal Vaskof02e3742015-08-05 16:27:02 +02004613/* logs directly */
4614static void
Radek Krejci48464ed2016-03-17 15:44:09 +01004615print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004616{
Michal Vaskof02e3742015-08-05 16:27:02 +02004617 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004618 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004619 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004620 break;
4621 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004622 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004623 break;
4624 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004625 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
4626 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02004627 break;
4628 case UNRES_TYPE_DER:
Radek Krejci48464ed2016-03-17 15:44:09 +01004629 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type",
4630 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value);
Michal Vaskof02e3742015-08-05 16:27:02 +02004631 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004632 case UNRES_IFFEAT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004633 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004634 break;
4635 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004636 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004637 break;
4638 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004639 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004640 break;
4641 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004642 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004643 break;
4644 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01004645 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004646 break;
4647 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01004648 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004649 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004650 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004651 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
4652 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01004653 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004654 default:
4655 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004656 break;
4657 }
4658}
4659
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004660/**
Michal Vaskobb211122015-08-19 14:03:11 +02004661 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004662 *
4663 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004664 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004665 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004666 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004667 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004668int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004669resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004670{
Radek Krejci010e54b2016-03-15 09:40:34 +01004671 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004672 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004673
4674 assert(unres);
4675
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02004676 LOGVRB("Resolving unresolved schema nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01004677 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02004678
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004679 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004680 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004681 unres_count = 0;
4682 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004683
4684 for (i = 0; i < unres->count; ++i) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02004685 /* we do not need to have UNRES_TYPE_IDENTREF resolved, we need its type's base only,
4686 * but UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers) */
4687 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)
4688 && (unres->type[i] != UNRES_TYPE_LEAFREF)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004689 continue;
4690 }
4691
Michal Vasko88c29542015-11-27 14:57:53 +01004692 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01004693 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004694 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004695 unres->type[i] = UNRES_RESOLVED;
4696 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004697 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004698 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004699 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02004700 /* print the error */
4701 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004702 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004703 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004704 }
Michal Vasko88c29542015-11-27 14:57:53 +01004705 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004706
Michal Vasko88c29542015-11-27 14:57:53 +01004707 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02004708 /* just print the errors */
4709 ly_vlog_hide(0);
4710
4711 for (i = 0; i < unres->count; ++i) {
4712 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)
4713 && (unres->type[i] != UNRES_TYPE_LEAFREF)) {
4714 continue;
4715 }
4716 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
4717 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004718 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004719 }
4720
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004721 /* the rest */
4722 for (i = 0; i < unres->count; ++i) {
4723 if (unres->type[i] == UNRES_RESOLVED) {
4724 continue;
4725 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004726
Radek Krejci48464ed2016-03-17 15:44:09 +01004727 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004728 if (rc == 0) {
4729 unres->type[i] = UNRES_RESOLVED;
4730 ++resolved;
4731 } else if (rc == -1) {
4732 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02004733 /* print the error */
4734 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
4735 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004736 }
4737 }
4738
Radek Krejci010e54b2016-03-15 09:40:34 +01004739 ly_vlog_hide(0);
4740
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004741 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004742 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
4743 * all the validation errors
4744 */
4745 for (i = 0; i < unres->count; ++i) {
4746 if (unres->type[i] == UNRES_RESOLVED) {
4747 continue;
4748 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004749 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004750 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004751 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004752 }
4753
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02004754 LOGVRB("All schema nodes and constraints resolved.");
Radek Krejcic071c542016-01-27 14:57:51 +01004755 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004756 return EXIT_SUCCESS;
4757}
4758
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004759/**
Michal Vaskobb211122015-08-19 14:03:11 +02004760 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004761 *
4762 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004763 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004764 * @param[in] item Item to resolve. Type determined by \p type.
4765 * @param[in] type Type of the unresolved item.
4766 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004767 *
4768 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4769 */
4770int
Radek Krejci48464ed2016-03-17 15:44:09 +01004771unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
4772 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004773{
Radek Krejci48464ed2016-03-17 15:44:09 +01004774 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 +02004775}
4776
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004777/**
Michal Vaskobb211122015-08-19 14:03:11 +02004778 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004779 *
4780 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004781 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004782 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004783 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004784 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004785 *
4786 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4787 */
4788int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004789unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01004790 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004791{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004792 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004793 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01004794 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004795
Michal Vasko9bf425b2015-10-22 11:42:03 +02004796 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4797 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004798
Radek Krejci010e54b2016-03-15 09:40:34 +01004799 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004800 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004801 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004802 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004803 if (rc == -1 && ly_errno == LY_EVALID) {
4804 path = strdup(ly_errpath());
4805 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
4806 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
4807 free(path);
4808 free(msg);
4809 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004810 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004811 }
4812
Radek Krejci48464ed2016-03-17 15:44:09 +01004813 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02004814
Michal Vasko88c29542015-11-27 14:57:53 +01004815 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4816 if (type == UNRES_TYPE_DER) {
4817 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01004818 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
4819 lyxml_unlink_elem(mod->ctx, yin, 1);
4820 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4821 }
Michal Vasko88c29542015-11-27 14:57:53 +01004822 }
4823
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004824 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004825 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4826 if (!unres->item) {
4827 LOGMEM;
4828 return -1;
4829 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004830 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004831 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4832 if (!unres->type) {
4833 LOGMEM;
4834 return -1;
4835 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004836 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004837 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4838 if (!unres->str_snode) {
4839 LOGMEM;
4840 return -1;
4841 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004842 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004843 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4844 if (!unres->module) {
4845 LOGMEM;
4846 return -1;
4847 }
4848 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004849
4850 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004851}
4852
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004853/**
Michal Vaskobb211122015-08-19 14:03:11 +02004854 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004855 *
4856 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004857 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004858 * @param[in] item Old item to be resolved.
4859 * @param[in] type Type of the old unresolved item.
4860 * @param[in] new_item New item to use in the duplicate.
4861 *
4862 * @return EXIT_SUCCESS on success, -1 on error.
4863 */
Michal Vaskodad19402015-08-06 09:51:53 +02004864int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004865unres_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 +02004866{
4867 int i;
4868
Michal Vaskocf024702015-10-08 15:01:42 +02004869 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004870
Michal Vasko0bd29d12015-08-19 11:45:49 +02004871 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004872
4873 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004874 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004875 }
4876
Michal Vasko0d204592015-10-07 09:50:04 +02004877 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004878 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004879 LOGINT;
4880 return -1;
4881 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004882 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004883 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004884 LOGINT;
4885 return -1;
4886 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004887 }
Michal Vaskodad19402015-08-06 09:51:53 +02004888
4889 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004890}
4891
Michal Vaskof02e3742015-08-05 16:27:02 +02004892/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004893int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004894unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004895{
4896 uint32_t ret = -1, i;
4897
4898 for (i = 0; i < unres->count; ++i) {
4899 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4900 ret = i;
4901 break;
4902 }
4903 }
4904
4905 return ret;
4906}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004907
Michal Vasko88c29542015-11-27 14:57:53 +01004908void
Radek Krejcic071c542016-01-27 14:57:51 +01004909unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004910{
4911 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004912 unsigned int unresolved = 0;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004913 struct lyxml_elem *yin;
4914 struct yang_type *yang;
Michal Vasko88c29542015-11-27 14:57:53 +01004915
Radek Krejcic071c542016-01-27 14:57:51 +01004916 if (!unres || !(*unres)) {
4917 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004918 }
4919
Radek Krejcic071c542016-01-27 14:57:51 +01004920 assert(module || (*unres)->count == 0);
4921
4922 for (i = 0; i < (*unres)->count; ++i) {
4923 if ((*unres)->module[i] != module) {
4924 if ((*unres)->type[i] != UNRES_RESOLVED) {
4925 unresolved++;
4926 }
4927 continue;
4928 }
4929 if ((*unres)->type[i] == UNRES_TYPE_DER) {
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004930 yin = (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der;
4931 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
4932 yang =(struct yang_type *)yin;
Pavol Vican6b072512016-04-04 10:50:21 +02004933 yang->type->base = yang->base;
Pavol Vican5f0316a2016-04-05 21:21:11 +02004934 lydict_remove(module->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01004935 free(yang);
4936 } else {
4937 lyxml_free(module->ctx, yin);
4938 }
Radek Krejcic071c542016-01-27 14:57:51 +01004939 }
4940 (*unres)->type[i] = UNRES_RESOLVED;
4941 }
4942
4943 if (!module || (!unresolved && !module->type)) {
4944 free((*unres)->item);
4945 free((*unres)->type);
4946 free((*unres)->str_snode);
4947 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01004948 free((*unres));
4949 (*unres) = NULL;
4950 }
Michal Vasko88c29542015-11-27 14:57:53 +01004951}
4952
Michal Vasko8bcdf292015-08-19 14:04:43 +02004953/**
4954 * @brief Resolve a single unres data item. Logs directly.
4955 *
Michal Vaskocf024702015-10-08 15:01:42 +02004956 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02004957 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004958 *
4959 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4960 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004961int
Radek Krejci48464ed2016-03-17 15:44:09 +01004962resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004963{
4964 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004965 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004966 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004967 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02004968 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004969 struct unres_data matches;
4970
4971 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004972 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004973 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004974
Michal Vaskocf024702015-10-08 15:01:42 +02004975 switch (type) {
4976 case UNRES_LEAFREF:
4977 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vasko2471e7f2016-04-11 11:00:15 +02004978 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
4979 if (resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches) == -1) {
4980 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004981 }
4982
4983 /* check that value matches */
4984 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004985 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004986 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004987 break;
4988 }
4989 }
4990
Michal Vaskocf024702015-10-08 15:01:42 +02004991 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004992
Michal Vaskocf024702015-10-08 15:01:42 +02004993 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004994 /* reference not found */
Michal Vasko6ac68282016-04-11 10:56:47 +02004995 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004996 return EXIT_FAILURE;
4997 }
Michal Vaskocf024702015-10-08 15:01:42 +02004998 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004999
Michal Vaskocf024702015-10-08 15:01:42 +02005000 case UNRES_INSTID:
Michal Vasko976a5f22016-05-18 13:28:42 +02005001 assert((sleaf->type.base == LY_TYPE_INST) || (sleaf->type.base == LY_TYPE_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02005002 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01005003 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01005004 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02005005 if (ly_errno) {
5006 return -1;
5007 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005008 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005009 return EXIT_FAILURE;
5010 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01005011 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02005012 }
5013 }
Michal Vaskocf024702015-10-08 15:01:42 +02005014 break;
5015
5016 case UNRES_WHEN:
Radek Krejci48464ed2016-03-17 15:44:09 +01005017 if ((rc = resolve_when(node))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005018 return rc;
5019 }
5020 break;
5021
Michal Vaskobf19d252015-10-08 15:39:17 +02005022 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01005023 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005024 return rc;
5025 }
5026 break;
5027
Michal Vaskoc4280842016-04-19 16:10:42 +02005028 case UNRES_EMPTYCONT:
5029 do {
5030 parent = node->parent;
5031 lyd_free(node);
5032 node = parent;
5033 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
5034 && !((struct lys_node_container *)node->schema)->presence);
5035 break;
5036
Michal Vaskocf024702015-10-08 15:01:42 +02005037 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02005038 LOGINT;
5039 return -1;
5040 }
5041
5042 return EXIT_SUCCESS;
5043}
5044
5045/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01005046 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02005047 *
5048 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02005049 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02005050 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01005051 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02005052 */
5053int
Radek Krejci0b7704f2016-03-18 12:16:14 +01005054unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02005055{
Radek Krejci03b71f72016-03-16 11:10:09 +01005056 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02005057 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
5058 || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02005059
Radek Krejci03b71f72016-03-16 11:10:09 +01005060 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01005061 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
5062 if (!unres->node) {
5063 LOGMEM;
5064 return -1;
5065 }
Michal Vaskocf024702015-10-08 15:01:42 +02005066 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01005067 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
5068 if (!unres->type) {
5069 LOGMEM;
5070 return -1;
5071 }
Michal Vaskocf024702015-10-08 15:01:42 +02005072 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02005073
Radek Krejci0b7704f2016-03-18 12:16:14 +01005074 if (type == UNRES_WHEN) {
5075 /* remove previous result */
5076 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005077 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005078
5079 return EXIT_SUCCESS;
5080}
5081
5082/**
5083 * @brief Resolve every unres data item in the structure. Logs directly.
5084 *
5085 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01005086 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
5087 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01005088 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005089 *
5090 * @return EXIT_SUCCESS on success, -1 on error.
5091 */
5092int
Radek Krejci0c0086a2016-03-24 15:20:28 +01005093resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005094{
Radek Krejci0c0086a2016-03-24 15:20:28 +01005095 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01005096 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01005097 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005098 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005099
Radek Krejci03b71f72016-03-16 11:10:09 +01005100 assert(unres);
Radek Krejci8ee1b562016-03-31 10:58:31 +02005101 assert((root && (*root)) || (options & LYD_OPT_NOAUTODEL));
Radek Krejci03b71f72016-03-16 11:10:09 +01005102
5103 if (!unres->count) {
5104 return EXIT_SUCCESS;
5105 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005106
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005107 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01005108 ly_vlog_hide(1);
5109
Radek Krejci0b7704f2016-03-18 12:16:14 +01005110 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01005111 ly_errno = LY_SUCCESS;
5112 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005113 do {
5114 progress = 0;
5115 for(i = 0; i < unres->count; i++) {
5116 if (unres->type[i] != UNRES_WHEN) {
5117 continue;
5118 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005119 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005120 /* count when-stmt nodes in unres list */
5121 when_stmt++;
5122 }
5123
5124 /* resolve when condition only when all parent when conditions are already resolved */
5125 for (parent = unres->node[i]->parent;
5126 parent && LYD_WHEN_DONE(parent->when_status);
5127 parent = parent->parent) {
5128 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
5129 /* the parent node was already unlinked, do not resolve this node,
5130 * it will be removed anyway, so just mark it as resolved
5131 */
5132 unres->node[i]->when_status |= LYD_WHEN_FALSE;
5133 unres->type[i] = UNRES_RESOLVED;
5134 resolved++;
5135 break;
5136 }
5137 }
5138 if (parent) {
5139 continue;
5140 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005141
Radek Krejci48464ed2016-03-17 15:44:09 +01005142 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005143 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005144 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
5145 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005146 /* false when condition */
5147 ly_vlog_hide(0);
5148 path = strdup(ly_errpath());
5149 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
5150 path[0] ? path : "", path[0] ? ")" : "");
5151 free(path);
5152 free(msg);
5153 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005154 } /* follows else */
5155
Radek Krejci0c0086a2016-03-24 15:20:28 +01005156 /* only unlink now, the subtree can contain another nodes stored in the unres list */
5157 /* if it has parent non-presence containers that would be empty, we should actually
5158 * remove the container
5159 */
5160 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
5161 for (parent = unres->node[i];
5162 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
5163 parent = parent->parent) {
5164 if (((struct lys_node_container *)parent->parent->schema)->presence) {
5165 /* presence container */
5166 break;
5167 }
5168 if (parent->next || parent->prev != parent) {
5169 /* non empty (the child we are in and we are going to remove is not the only child) */
5170 break;
5171 }
5172 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005173 unres->node[i] = parent;
5174 }
5175
Radek Krejci0b7704f2016-03-18 12:16:14 +01005176 /* auto-delete */
5177 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
5178 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01005179 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005180 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01005181 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005182
Radek Krejci0b7704f2016-03-18 12:16:14 +01005183 lyd_unlink(unres->node[i]);
5184 unres->type[i] = UNRES_DELETE;
5185 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01005186
5187 /* update the rest of unres items */
5188 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01005189 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01005190 continue;
5191 }
5192
5193 /* test if the node is in subtree to be deleted */
5194 for (parent = unres->node[j]; parent; parent = parent->parent) {
5195 if (parent == unres->node[i]) {
5196 /* yes, it is */
5197 unres->type[j] = UNRES_RESOLVED;
5198 resolved++;
5199 break;
5200 }
5201 }
5202 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005203 } else {
5204 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01005205 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01005206 ly_errno = LY_SUCCESS;
5207 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01005208 resolved++;
5209 progress = 1;
5210 } else if (rc == -1) {
5211 ly_vlog_hide(0);
5212 return -1;
5213 }
5214 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005215 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005216 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01005217
Radek Krejci0b7704f2016-03-18 12:16:14 +01005218 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01005219 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005220 ly_vlog_hide(0);
5221 path = strdup(ly_errpath());
5222 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
5223 path[0] ? path : "", path[0] ? ")" : "");
5224 free(path);
5225 free(msg);
5226 return -1;
5227 }
5228
5229 for (i = 0; del_items && i < unres->count; i++) {
5230 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
5231 if (unres->type[i] != UNRES_DELETE) {
5232 continue;
5233 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01005234 if (!unres->node[i]) {
5235 unres->type[i] = UNRES_RESOLVED;
5236 del_items--;
5237 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01005238 }
5239
5240 /* really remove the complete subtree */
5241 lyd_free(unres->node[i]);
5242 unres->type[i] = UNRES_RESOLVED;
5243 del_items--;
5244 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005245
5246 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005247 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005248 if (unres->type[i] == UNRES_RESOLVED) {
5249 continue;
5250 }
5251
Radek Krejci48464ed2016-03-17 15:44:09 +01005252 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005253 if (rc == 0) {
5254 unres->type[i] = UNRES_RESOLVED;
5255 resolved++;
5256 } else if (rc == -1) {
5257 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02005258 /* print only this last error */
5259 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005260 return -1;
5261 }
5262 }
5263
Radek Krejci010e54b2016-03-15 09:40:34 +01005264 ly_vlog_hide(0);
5265 if (resolved < unres->count) {
5266 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
5267 * all the validation errors
5268 */
5269 for (i = 0; i < unres->count; ++i) {
5270 if (unres->type[i] == UNRES_RESOLVED) {
5271 continue;
5272 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005273 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01005274 }
5275 return -1;
5276 }
5277
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005278 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01005279 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005280 return EXIT_SUCCESS;
5281}