blob: 5080ba4fee2f029db45f90cf073afe3690673c1f [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"
Michal Vasko88c29542015-11-27 14:57:53 +010028#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020029#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020030#include "tree_internal.h"
31
Michal Vasko730dfdf2015-08-11 14:48:05 +020032/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020033 * @brief Parse an identifier.
34 *
35 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
36 * identifier = (ALPHA / "_")
37 * *(ALPHA / DIGIT / "_" / "-" / ".")
38 *
Michal Vaskobb211122015-08-19 14:03:11 +020039 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020040 *
41 * @return Number of characters successfully parsed.
42 */
Michal Vasko249e6b52015-08-19 11:08:52 +020043int
Radek Krejci6dc53a22015-08-17 13:27:59 +020044parse_identifier(const char *id)
45{
46 int parsed = 0;
47
Michal Vasko1ab90bc2016-03-15 10:40:22 +010048 assert(id);
49
Radek Krejci6dc53a22015-08-17 13:27:59 +020050 if (((id[0] == 'x') || (id[0] == 'X'))
Michal Vasko1ab90bc2016-03-15 10:40:22 +010051 && (id[0] && ((id[1] == 'm') || (id[0] == 'M')))
52 && (id[1] && ((id[2] == 'l') || (id[2] == 'L')))) {
Radek Krejci6dc53a22015-08-17 13:27:59 +020053 return -parsed;
54 }
55
56 if (!isalpha(id[0]) && (id[0] != '_')) {
57 return -parsed;
58 }
59
60 ++parsed;
61 ++id;
62
63 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
64 ++parsed;
65 ++id;
66 }
67
68 return parsed;
69}
70
71/**
72 * @brief Parse a node-identifier.
73 *
Michal Vasko723e50c2015-10-20 15:20:29 +020074 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020075 *
Michal Vaskobb211122015-08-19 14:03:11 +020076 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020077 * @param[out] mod_name Points to the module name, NULL if there is not any.
78 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020079 * @param[out] name Points to the node name.
80 * @param[out] nam_len Length of the node name.
81 *
82 * @return Number of characters successfully parsed,
83 * positive on success, negative on failure.
84 */
85static int
Michal Vasko723e50c2015-10-20 15:20:29 +020086parse_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 +020087{
88 int parsed = 0, ret;
89
90 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020091 if (mod_name) {
92 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020093 }
Michal Vasko723e50c2015-10-20 15:20:29 +020094 if (mod_name_len) {
95 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020096 }
97 if (name) {
98 *name = NULL;
99 }
100 if (nam_len) {
101 *nam_len = 0;
102 }
103
104 if ((ret = parse_identifier(id)) < 1) {
105 return ret;
106 }
107
Michal Vasko723e50c2015-10-20 15:20:29 +0200108 if (mod_name) {
109 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200110 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200111 if (mod_name_len) {
112 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200113 }
114
115 parsed += ret;
116 id += ret;
117
118 /* there is prefix */
119 if (id[0] == ':') {
120 ++parsed;
121 ++id;
122
123 /* there isn't */
124 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200125 if (name && mod_name) {
126 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200127 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200128 if (mod_name) {
129 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200130 }
131
Michal Vasko723e50c2015-10-20 15:20:29 +0200132 if (nam_len && mod_name_len) {
133 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200134 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200135 if (mod_name_len) {
136 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200137 }
138
139 return parsed;
140 }
141
142 /* identifier (node name) */
143 if ((ret = parse_identifier(id)) < 1) {
144 return -parsed+ret;
145 }
146
147 if (name) {
148 *name = id;
149 }
150 if (nam_len) {
151 *nam_len = ret;
152 }
153
154 return parsed+ret;
155}
156
157/**
158 * @brief Parse a path-predicate (leafref).
159 *
160 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
161 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
162 *
Michal Vaskobb211122015-08-19 14:03:11 +0200163 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200164 * @param[out] prefix Points to the prefix, NULL if there is not any.
165 * @param[out] pref_len Length of the prefix, 0 if there is not any.
166 * @param[out] name Points to the node name.
167 * @param[out] nam_len Length of the node name.
168 * @param[out] path_key_expr Points to the path-key-expr.
169 * @param[out] pke_len Length of the path-key-expr.
170 * @param[out] has_predicate Flag to mark whether there is another predicate following.
171 *
172 * @return Number of characters successfully parsed,
173 * positive on success, negative on failure.
174 */
175static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200176parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
177 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200178{
179 const char *ptr;
180 int parsed = 0, ret;
181
182 assert(id);
183 if (prefix) {
184 *prefix = NULL;
185 }
186 if (pref_len) {
187 *pref_len = 0;
188 }
189 if (name) {
190 *name = NULL;
191 }
192 if (nam_len) {
193 *nam_len = 0;
194 }
195 if (path_key_expr) {
196 *path_key_expr = NULL;
197 }
198 if (pke_len) {
199 *pke_len = 0;
200 }
201 if (has_predicate) {
202 *has_predicate = 0;
203 }
204
205 if (id[0] != '[') {
206 return -parsed;
207 }
208
209 ++parsed;
210 ++id;
211
212 while (isspace(id[0])) {
213 ++parsed;
214 ++id;
215 }
216
217 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
218 return -parsed+ret;
219 }
220
221 parsed += ret;
222 id += ret;
223
224 while (isspace(id[0])) {
225 ++parsed;
226 ++id;
227 }
228
229 if (id[0] != '=') {
230 return -parsed;
231 }
232
233 ++parsed;
234 ++id;
235
236 while (isspace(id[0])) {
237 ++parsed;
238 ++id;
239 }
240
241 if ((ptr = strchr(id, ']')) == NULL) {
242 return -parsed;
243 }
244
245 --ptr;
246 while (isspace(ptr[0])) {
247 --ptr;
248 }
249 ++ptr;
250
251 ret = ptr-id;
252 if (path_key_expr) {
253 *path_key_expr = id;
254 }
255 if (pke_len) {
256 *pke_len = ret;
257 }
258
259 parsed += ret;
260 id += ret;
261
262 while (isspace(id[0])) {
263 ++parsed;
264 ++id;
265 }
266
267 assert(id[0] == ']');
268
269 if (id[1] == '[') {
270 *has_predicate = 1;
271 }
272
273 return parsed+1;
274}
275
276/**
277 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
278 * the ".." and the first node-identifier, other calls parse a single
279 * node-identifier each.
280 *
281 * path-key-expr = current-function-invocation *WSP "/" *WSP
282 * rel-path-keyexpr
283 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
284 * *(node-identifier *WSP "/" *WSP)
285 * node-identifier
286 *
Michal Vaskobb211122015-08-19 14:03:11 +0200287 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200288 * @param[out] prefix Points to the prefix, NULL if there is not any.
289 * @param[out] pref_len Length of the prefix, 0 if there is not any.
290 * @param[out] name Points to the node name.
291 * @param[out] nam_len Length of the node name.
292 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
293 * must not be changed between consecutive calls.
294 * @return Number of characters successfully parsed,
295 * positive on success, negative on failure.
296 */
297static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200298parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
299 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200300{
301 int parsed = 0, ret, par_times = 0;
302
303 assert(id);
304 assert(parent_times);
305 if (prefix) {
306 *prefix = NULL;
307 }
308 if (pref_len) {
309 *pref_len = 0;
310 }
311 if (name) {
312 *name = NULL;
313 }
314 if (nam_len) {
315 *nam_len = 0;
316 }
317
318 if (!*parent_times) {
319 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
320 if (strncmp(id, "current()", 9)) {
321 return -parsed;
322 }
323
324 parsed += 9;
325 id += 9;
326
327 while (isspace(id[0])) {
328 ++parsed;
329 ++id;
330 }
331
332 if (id[0] != '/') {
333 return -parsed;
334 }
335
336 ++parsed;
337 ++id;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 /* rel-path-keyexpr */
345 if (strncmp(id, "..", 2)) {
346 return -parsed;
347 }
348 ++par_times;
349
350 parsed += 2;
351 id += 2;
352
353 while (isspace(id[0])) {
354 ++parsed;
355 ++id;
356 }
357 }
358
359 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
360 *
361 * first parent reference with whitespaces already parsed
362 */
363 if (id[0] != '/') {
364 return -parsed;
365 }
366
367 ++parsed;
368 ++id;
369
370 while (isspace(id[0])) {
371 ++parsed;
372 ++id;
373 }
374
375 while (!strncmp(id, "..", 2) && !*parent_times) {
376 ++par_times;
377
378 parsed += 2;
379 id += 2;
380
381 while (isspace(id[0])) {
382 ++parsed;
383 ++id;
384 }
385
386 if (id[0] != '/') {
387 return -parsed;
388 }
389
390 ++parsed;
391 ++id;
392
393 while (isspace(id[0])) {
394 ++parsed;
395 ++id;
396 }
397 }
398
399 if (!*parent_times) {
400 *parent_times = par_times;
401 }
402
403 /* all parent references must be parsed at this point */
404 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
405 return -parsed+ret;
406 }
407
408 parsed += ret;
409 id += ret;
410
411 return parsed;
412}
413
414/**
415 * @brief Parse path-arg (leafref).
416 *
417 * path-arg = absolute-path / relative-path
418 * absolute-path = 1*("/" (node-identifier *path-predicate))
419 * relative-path = 1*(".." "/") descendant-path
420 *
Michal Vaskobb211122015-08-19 14:03:11 +0200421 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200422 * @param[out] prefix Points to the prefix, NULL if there is not any.
423 * @param[out] pref_len Length of the prefix, 0 if there is not any.
424 * @param[out] name Points to the node name.
425 * @param[out] nam_len Length of the node name.
426 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
427 * must not be changed between consecutive calls. -1 if the
428 * path is relative.
429 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
430 *
431 * @return Number of characters successfully parsed,
432 * positive on success, negative on failure.
433 */
434static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200435parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
436 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200437{
438 int parsed = 0, ret, par_times = 0;
439
440 assert(id);
441 assert(parent_times);
442 if (prefix) {
443 *prefix = NULL;
444 }
445 if (pref_len) {
446 *pref_len = 0;
447 }
448 if (name) {
449 *name = NULL;
450 }
451 if (nam_len) {
452 *nam_len = 0;
453 }
454 if (has_predicate) {
455 *has_predicate = 0;
456 }
457
458 if (!*parent_times && !strncmp(id, "..", 2)) {
459 ++par_times;
460
461 parsed += 2;
462 id += 2;
463
464 while (!strncmp(id, "/..", 3)) {
465 ++par_times;
466
467 parsed += 3;
468 id += 3;
469 }
470 }
471
472 if (!*parent_times) {
473 if (par_times) {
474 *parent_times = par_times;
475 } else {
476 *parent_times = -1;
477 }
478 }
479
480 if (id[0] != '/') {
481 return -parsed;
482 }
483
484 /* skip '/' */
485 ++parsed;
486 ++id;
487
488 /* node-identifier ([prefix:]identifier) */
489 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
490 return -parsed-ret;
491 }
492
493 parsed += ret;
494 id += ret;
495
496 /* there is no predicate */
497 if ((id[0] == '/') || !id[0]) {
498 return parsed;
499 } else if (id[0] != '[') {
500 return -parsed;
501 }
502
503 if (has_predicate) {
504 *has_predicate = 1;
505 }
506
507 return parsed;
508}
509
510/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200511 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200512 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200513 *
514 * instance-identifier = 1*("/" (node-identifier *predicate))
515 *
Michal Vaskobb211122015-08-19 14:03:11 +0200516 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200517 * @param[out] model Points to the model name.
518 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200519 * @param[out] name Points to the node name.
520 * @param[out] nam_len Length of the node name.
521 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
522 *
523 * @return Number of characters successfully parsed,
524 * positive on success, negative on failure.
525 */
526static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200527parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
528 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200529{
530 int parsed = 0, ret;
531
532 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200533 if (model) {
534 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200535 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200536 if (mod_len) {
537 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200538 }
539 if (name) {
540 *name = NULL;
541 }
542 if (nam_len) {
543 *nam_len = 0;
544 }
545 if (has_predicate) {
546 *has_predicate = 0;
547 }
548
549 if (id[0] != '/') {
550 return -parsed;
551 }
552
553 ++parsed;
554 ++id;
555
Michal Vasko1f2cc332015-08-19 11:18:32 +0200556 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200557 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200558 } else if (model && !*model) {
559 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200560 }
561
562 parsed += ret;
563 id += ret;
564
565 if ((id[0] == '[') && has_predicate) {
566 *has_predicate = 1;
567 }
568
569 return parsed;
570}
571
572/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200573 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200574 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575 *
576 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
577 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
578 * ((DQUOTE string DQUOTE) /
579 * (SQUOTE string SQUOTE))
580 * pos = non-negative-integer-value
581 *
Michal Vaskobb211122015-08-19 14:03:11 +0200582 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200583 * @param[out] model Points to the model name.
584 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200585 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
586 * @param[out] nam_len Length of the node name.
587 * @param[out] value Value the node-identifier must have (string from the grammar),
588 * NULL if there is not any.
589 * @param[out] val_len Length of the value, 0 if there is not any.
590 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
591 *
592 * @return Number of characters successfully parsed,
593 * positive on success, negative on failure.
594 */
595static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200596parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
597 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200598{
599 const char *ptr;
600 int parsed = 0, ret;
601 char quote;
602
603 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200604 if (model) {
605 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200606 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200607 if (mod_len) {
608 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609 }
610 if (name) {
611 *name = NULL;
612 }
613 if (nam_len) {
614 *nam_len = 0;
615 }
616 if (value) {
617 *value = NULL;
618 }
619 if (val_len) {
620 *val_len = 0;
621 }
622 if (has_predicate) {
623 *has_predicate = 0;
624 }
625
626 if (id[0] != '[') {
627 return -parsed;
628 }
629
630 ++parsed;
631 ++id;
632
633 while (isspace(id[0])) {
634 ++parsed;
635 ++id;
636 }
637
638 /* pos */
639 if (isdigit(id[0])) {
640 if (name) {
641 *name = id;
642 }
643
644 if (id[0] == '0') {
645 ++parsed;
646 ++id;
647
648 if (isdigit(id[0])) {
649 return -parsed;
650 }
651 }
652
653 while (isdigit(id[0])) {
654 ++parsed;
655 ++id;
656 }
657
658 if (nam_len) {
659 *nam_len = id-(*name);
660 }
661
662 /* "." */
663 } else if (id[0] == '.') {
664 if (name) {
665 *name = id;
666 }
667 if (nam_len) {
668 *nam_len = 1;
669 }
670
671 ++parsed;
672 ++id;
673
674 /* node-identifier */
675 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200676 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200677 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200678 } else if (model && !*model) {
679 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200680 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200681
682 parsed += ret;
683 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 }
685
686 while (isspace(id[0])) {
687 ++parsed;
688 ++id;
689 }
690
691 if (id[0] != '=') {
692 return -parsed;
693 }
694
695 ++parsed;
696 ++id;
697
698 while (isspace(id[0])) {
699 ++parsed;
700 ++id;
701 }
702
703 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
704 if ((id[0] == '\"') || (id[0] == '\'')) {
705 quote = id[0];
706
707 ++parsed;
708 ++id;
709
710 if ((ptr = strchr(id, quote)) == NULL) {
711 return -parsed;
712 }
713 ret = ptr-id;
714
715 if (value) {
716 *value = id;
717 }
718 if (val_len) {
719 *val_len = ret;
720 }
721
722 parsed += ret+1;
723 id += ret+1;
724 } else {
725 return -parsed;
726 }
727
728 while (isspace(id[0])) {
729 ++parsed;
730 ++id;
731 }
732
733 if (id[0] != ']') {
734 return -parsed;
735 }
736
737 ++parsed;
738 ++id;
739
740 if ((id[0] == '[') && has_predicate) {
741 *has_predicate = 1;
742 }
743
744 return parsed;
745}
746
747/**
748 * @brief Parse schema-nodeid.
749 *
750 * schema-nodeid = absolute-schema-nodeid /
751 * descendant-schema-nodeid
752 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200753 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200754 * node-identifier
755 * absolute-schema-nodeid
756 *
Michal Vaskobb211122015-08-19 14:03:11 +0200757 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200758 * @param[out] mod_name Points to the module name, NULL if there is not any.
759 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200760 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200761 * @param[out] nam_len Length of the node name.
762 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
763 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100764 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
765 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200766 *
767 * @return Number of characters successfully parsed,
768 * positive on success, negative on failure.
769 */
Michal Vasko22448d32016-03-16 13:17:29 +0100770int
Michal Vasko723e50c2015-10-20 15:20:29 +0200771parse_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 +0100772 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200773{
774 int parsed = 0, ret;
775
776 assert(id);
777 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200778 if (mod_name) {
779 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200780 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200781 if (mod_name_len) {
782 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200783 }
784 if (name) {
785 *name = NULL;
786 }
787 if (nam_len) {
788 *nam_len = 0;
789 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100790 if (has_predicate) {
791 *has_predicate = 0;
792 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200793
794 if (id[0] != '/') {
795 if (*is_relative != -1) {
796 return -parsed;
797 } else {
798 *is_relative = 1;
799 }
Michal Vasko48935352016-03-29 11:52:36 +0200800 if (!strncmp(id, "./", 2)) {
801 parsed += 2;
802 id += 2;
803 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200804 } else {
805 if (*is_relative == -1) {
806 *is_relative = 0;
807 }
808 ++parsed;
809 ++id;
810 }
811
Michal Vasko723e50c2015-10-20 15:20:29 +0200812 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200813 return -parsed+ret;
814 }
815
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100816 parsed += ret;
817 id += ret;
818
819 if ((id[0] == '[') && has_predicate) {
820 *has_predicate = 1;
821 }
822
823 return parsed;
824}
825
826/**
827 * @brief Parse schema predicate (special format internally used).
828 *
829 * predicate = "[" *WSP predicate-expr *WSP "]"
830 * predicate-expr = identifier / key-with-value
831 * key-with-value = identifier *WSP "=" *WSP
832 * ((DQUOTE string DQUOTE) /
833 * (SQUOTE string SQUOTE))
834 *
835 * @param[in] id Identifier to use.
836 * @param[out] name Points to the list key name.
837 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100838 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100839 * @param[out] val_len Length of \p value.
840 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
841 */
Michal Vasko22448d32016-03-16 13:17:29 +0100842int
Michal Vasko3547c532016-03-14 09:40:50 +0100843parse_schema_list_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
844 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100845{
846 const char *ptr;
847 int parsed = 0, ret;
848 char quote;
849
850 assert(id);
851 if (name) {
852 *name = NULL;
853 }
854 if (nam_len) {
855 *nam_len = 0;
856 }
857 if (value) {
858 *value = NULL;
859 }
860 if (val_len) {
861 *val_len = 0;
862 }
863 if (has_predicate) {
864 *has_predicate = 0;
865 }
866
867 if (id[0] != '[') {
868 return -parsed;
869 }
870
871 ++parsed;
872 ++id;
873
874 while (isspace(id[0])) {
875 ++parsed;
876 ++id;
877 }
878
Michal Vasko22448d32016-03-16 13:17:29 +0100879 /* identifier */
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100880 if ((ret = parse_identifier(id)) < 1) {
881 return -parsed + ret;
882 }
883 if (name) {
884 *name = id;
885 }
886 if (nam_len) {
887 *nam_len = ret;
888 }
889
890 parsed += ret;
891 id += ret;
892
893 while (isspace(id[0])) {
894 ++parsed;
895 ++id;
896 }
897
898 /* there is value as well */
899 if (id[0] == '=') {
900 ++parsed;
901 ++id;
902
903 while (isspace(id[0])) {
904 ++parsed;
905 ++id;
906 }
907
908 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
909 if ((id[0] == '\"') || (id[0] == '\'')) {
910 quote = id[0];
911
912 ++parsed;
913 ++id;
914
915 if ((ptr = strchr(id, quote)) == NULL) {
916 return -parsed;
917 }
918 ret = ptr - id;
919
920 if (value) {
921 *value = id;
922 }
923 if (val_len) {
924 *val_len = ret;
925 }
926
927 parsed += ret + 1;
928 id += ret + 1;
929 } else {
930 return -parsed;
931 }
932
933 while (isspace(id[0])) {
934 ++parsed;
935 ++id;
936 }
Michal Vasko22448d32016-03-16 13:17:29 +0100937 } else if (value) {
938 /* if value was expected, it's mandatory */
939 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100940 }
941
942 if (id[0] != ']') {
943 return -parsed;
944 }
945
946 ++parsed;
947 ++id;
948
949 if ((id[0] == '[') && has_predicate) {
950 *has_predicate = 1;
951 }
952
953 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200954}
955
956/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100957 * @brief Resolve (find) a data node based on a schema-nodeid.
958 *
959 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
960 * module).
961 *
962 */
963struct lyd_node *
964resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
965{
966 char *str, *token, *p;
967 struct lyd_node *result = start, *iter;
968 const struct lys_node *schema = NULL;
969
970 assert(nodeid && start);
971
972 if (nodeid[0] == '/') {
973 return NULL;
974 }
975
976 str = p = strdup(nodeid);
977 if (!str) {
978 LOGMEM;
979 return NULL;
980 }
981 while (p) {
982 token = p;
983 p = strchr(p, '/');
984 if (p) {
985 *p = '\0';
986 p++;
987 }
988
989 schema = NULL;
990 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
991 free(str);
992 return NULL;
993 }
994
995 LY_TREE_FOR(result, iter) {
996 if (iter->schema == schema) {
997 break;
998 }
999 }
1000
1001 if (!p) {
1002 /* final result */
1003 result = iter;
1004 } else {
1005 result = iter->child;
1006 }
1007 }
1008 free(str);
1009
1010 return result;
1011}
1012
1013/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1014int
1015resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1016 const struct lys_node **ret)
1017{
1018 const char *name, *mod_name, *id;
1019 const struct lys_node *sibling;
1020 int r, nam_len, mod_name_len, is_relative = -1;
1021 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001022 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001023
1024 assert(nodeid && (start || module) && !(start && module) && ret);
1025
1026 id = nodeid;
1027
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001028 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 +01001029 return ((id - nodeid) - r) + 1;
1030 }
1031 id += r;
1032
1033 if ((is_relative && !start) || (!is_relative && !module)) {
1034 return -1;
1035 }
1036
1037 /* descendant-schema-nodeid */
1038 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001039 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001040
1041 /* absolute-schema-nodeid */
1042 } else {
1043 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001044 if (!start_mod) {
1045 return -1;
1046 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001047 start = start_mod->data;
1048 }
1049
1050 while (1) {
1051 sibling = NULL;
1052 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1053 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1054 /* name match */
1055 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1056 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
1057 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
1058
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 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001064 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001065 continue;
1066 }
1067
1068 /* the result node? */
1069 if (!id[0]) {
1070 *ret = sibling;
1071 return EXIT_SUCCESS;
1072 }
1073
1074 /* check for shorthand cases - then 'start' does not change */
1075 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1076 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001077 /* move down the tree, if possible */
1078 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1079 return -1;
1080 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001081 start = sibling->child;
1082 }
1083 break;
1084 }
1085 }
1086
1087 /* no match */
1088 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001089 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001090 return EXIT_SUCCESS;
1091 }
1092
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001093 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 +01001094 return ((id - nodeid) - r) + 1;
1095 }
1096 id += r;
1097 }
1098
1099 /* cannot get here */
1100 LOGINT;
1101 return -1;
1102}
1103
1104/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1105int
1106resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
1107 const struct lys_node **ret)
1108{
1109 const char *name, *mod_name, *id;
1110 const struct lys_node *sibling;
1111 int r, nam_len, mod_name_len, is_relative = -1;
1112 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001113 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001114
1115 assert(nodeid && start && ret);
1116 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1117
1118 id = nodeid;
1119 module = start->module;
1120
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001121 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 +01001122 return ((id - nodeid) - r) + 1;
1123 }
1124 id += r;
1125
1126 if (!is_relative) {
1127 return -1;
1128 }
1129
1130 while (1) {
1131 sibling = NULL;
1132 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1133 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1134 /* name match */
1135 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1136
1137 /* module check */
1138 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1139 if (!prefix_mod) {
1140 return -1;
1141 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001142 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001143 continue;
1144 }
1145
1146 /* the result node? */
1147 if (!id[0]) {
1148 if (!(sibling->nodetype & ret_nodetype)) {
1149 /* wrong node type, too bad */
1150 continue;
1151 }
1152 *ret = sibling;
1153 return EXIT_SUCCESS;
1154 }
1155
1156 /* check for shorthand cases - then 'start' does not change */
1157 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1158 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001159 /* move down the tree, if possible */
1160 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1161 return -1;
1162 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001163 start = sibling->child;
1164 }
1165 break;
1166 }
1167 }
1168
1169 /* no match */
1170 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001171 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001172 return EXIT_SUCCESS;
1173 }
1174
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001175 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 +01001176 return ((id - nodeid) - r) + 1;
1177 }
1178 id += r;
1179 }
1180
1181 /* cannot get here */
1182 LOGINT;
1183 return -1;
1184}
1185
1186/* choice default */
1187int
1188resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1189{
1190 /* cannot actually be a path */
1191 if (strchr(nodeid, '/')) {
1192 return -1;
1193 }
1194
1195 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1196}
1197
1198/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1199static int
1200resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1201{
1202 const struct lys_module *module;
1203 const char *mod_prefix, *name;
1204 int i, mod_prefix_len, nam_len;
1205
1206 /* parse the identifier, it must be parsed on one call */
1207 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1208 return -i + 1;
1209 }
1210
1211 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1212 if (!module) {
1213 return -1;
1214 }
1215 if (module != start->module) {
1216 start = module->data;
1217 }
1218
1219 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1220
1221 return EXIT_SUCCESS;
1222}
1223
1224int
1225resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1226 const struct lys_node **ret)
1227{
1228 const char *name, *mod_name, *id;
1229 const struct lys_node *sibling, *start;
1230 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko4f0dad02016-02-15 14:08:23 +01001231 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001232
1233 assert(nodeid && module && ret);
1234 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1235
1236 id = nodeid;
1237 start = module->data;
1238
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001239 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 +01001240 return ((id - nodeid) - r) + 1;
1241 }
1242 id += r;
1243
1244 if (is_relative) {
1245 return -1;
1246 }
1247
1248 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001249 if (!abs_start_mod) {
1250 return -1;
1251 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001252
1253 while (1) {
1254 sibling = NULL;
1255 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1256 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1257 /* name match */
1258 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1259
1260 /* module check */
1261 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1262 if (!prefix_mod) {
1263 return -1;
1264 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001265 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001266 continue;
1267 }
1268
1269 /* the result node? */
1270 if (!id[0]) {
1271 if (!(sibling->nodetype & ret_nodetype)) {
1272 /* wrong node type, too bad */
1273 continue;
1274 }
1275 *ret = sibling;
1276 return EXIT_SUCCESS;
1277 }
1278
1279 /* check for shorthand cases - then 'start' does not change */
1280 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1281 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001282 /* move down the tree, if possible */
1283 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1284 return -1;
1285 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001286 start = sibling->child;
1287 }
1288 break;
1289 }
1290 }
1291
1292 /* no match */
1293 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001294 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001295 return EXIT_SUCCESS;
1296 }
1297
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001298 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 +01001299 return ((id - nodeid) - r) + 1;
1300 }
1301 id += r;
1302 }
1303
1304 /* cannot get here */
1305 LOGINT;
1306 return -1;
1307}
1308
Michal Vaskoe733d682016-03-14 09:08:27 +01001309static int
Michal Vasko3547c532016-03-14 09:40:50 +01001310resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001311{
1312 const char *name;
1313 int nam_len, has_predicate, i;
1314
Michal Vasko3547c532016-03-14 09:40:50 +01001315 if ((i = parse_schema_list_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001316 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001317 return -1;
1318 }
1319
1320 predicate += i;
1321 *parsed += i;
1322
1323 for (i = 0; i < list->keys_size; ++i) {
1324 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1325 break;
1326 }
1327 }
1328
1329 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001330 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001331 return -1;
1332 }
1333
1334 /* more predicates? */
1335 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001336 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001337 }
1338
1339 return 0;
1340}
1341
1342/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
1343const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001344resolve_json_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001345{
Radek Krejcib3ecac22016-03-24 10:35:43 +01001346 char *str, module_name[LY_MODULE_NAME_MAX_LEN + 1];
Michal Vasko3edeaf72016-02-11 13:17:43 +01001347 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001348 const struct lys_node *sibling;
Michal Vaskoe733d682016-03-14 09:08:27 +01001349 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001350 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001351 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001352
Michal Vasko3547c532016-03-14 09:40:50 +01001353 assert(nodeid && (ctx || start));
1354 if (!ctx) {
1355 ctx = start->module->ctx;
1356 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001357
1358 id = nodeid;
1359
Michal Vaskoe733d682016-03-14 09:08:27 +01001360 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 +01001361 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001362 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001363 }
1364 id += r;
1365
1366 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001367 assert(start);
1368 start = start->child;
1369 if (!start) {
1370 /* no descendants, fail for sure */
Michal Vasko43c300e2016-03-22 12:54:27 +01001371 LOGVAL(LYE_PATH_INNODE, LY_VLOG_NONE, NULL, name);
Michal Vasko3547c532016-03-14 09:40:50 +01001372 return NULL;
1373 }
1374 module = start->module;
1375 } else {
1376 if (!mod_name) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001377 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL, name);
Michal Vasko3547c532016-03-14 09:40:50 +01001378 return NULL;
1379 }
1380
1381 str = strndup(mod_name, mod_name_len);
1382 module = ly_ctx_get_module(ctx, str, NULL);
1383 free(str);
1384 if (!module) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001385 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vasko3547c532016-03-14 09:40:50 +01001386 return NULL;
1387 }
1388 start = module->data;
1389
1390 /* now it's as if there was no module name */
1391 mod_name = NULL;
1392 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001393 }
1394
Michal Vaskoe733d682016-03-14 09:08:27 +01001395 prev_mod = module;
1396
Michal Vasko3edeaf72016-02-11 13:17:43 +01001397 while (1) {
1398 sibling = NULL;
1399 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1400 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1401 /* name match */
1402 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1403
1404 /* module check */
1405 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01001406 if (mod_name_len > LY_MODULE_NAME_MAX_LEN) {
1407 LOGINT;
1408 return NULL;
1409 }
1410 strncpy(module_name, mod_name, mod_name_len);
1411 module_name[mod_name_len] = '\0';
1412 /* will also find an augment module */
1413 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001414 if (!prefix_mod) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001415 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001416 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001417 }
1418 } else {
1419 prefix_mod = prev_mod;
1420 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001421 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001422 continue;
1423 }
1424
Michal Vaskoe733d682016-03-14 09:08:27 +01001425 /* do we have some predicates on it? */
1426 if (has_predicate) {
1427 r = 0;
1428 if (sibling->nodetype != LYS_LIST) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001429 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001430 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001431 } else if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001432 return NULL;
1433 }
1434 id += r;
1435 }
1436
Michal Vasko3edeaf72016-02-11 13:17:43 +01001437 /* the result node? */
1438 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001439 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001440 }
1441
1442 /* check for shorthand cases - then 'start' does not change */
1443 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1444 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001445 /* move down the tree, if possible */
1446 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001447 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01001448 return NULL;
1449 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001450 start = sibling->child;
1451 }
1452
1453 /* update prev mod */
1454 prev_mod = start->module;
1455 break;
1456 }
1457 }
1458
1459 /* no match */
1460 if (!sibling) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001461 LOGVAL(LYE_PATH_INNODE, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001462 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001463 }
1464
Michal Vaskoe733d682016-03-14 09:08:27 +01001465 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 +01001466 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001467 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001468 }
1469 id += r;
1470 }
1471
1472 /* cannot get here */
1473 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001474 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001475}
1476
Michal Vasko22448d32016-03-16 13:17:29 +01001477static int
1478resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
1479{
1480 const char *name, *value;
1481 int nam_len, val_len, has_predicate = 1, r;
1482 uint16_t i;
1483 struct ly_set *keys;
1484
Radek Krejci61a86c62016-03-24 11:06:44 +01001485 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01001486 assert(node->schema->nodetype == LYS_LIST);
1487
1488 keys = lyd_get_list_keys(node);
1489
1490 for (i = 0; i < keys->number; ++i) {
1491 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001492 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001493 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001494 }
1495
1496 if ((r = parse_schema_list_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001497 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Radek Krejciba5cec62016-03-24 10:40:29 +01001498 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001499 }
1500
1501 predicate += r;
1502 *parsed += r;
1503
Radek Krejci8f08df12016-03-21 11:11:30 +01001504 if (strncmp(keys->set.d[i]->schema->name, name, nam_len) || keys->set.d[i]->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001505 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001506 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001507 }
1508
1509 /* value does not match */
Radek Krejci8f08df12016-03-21 11:11:30 +01001510 if (strncmp(((struct lyd_node_leaf_list *)keys->set.d[i])->value_str, value, val_len)
1511 || ((struct lyd_node_leaf_list *)keys->set.d[i])->value_str[val_len]) {
Radek Krejciba5cec62016-03-24 10:40:29 +01001512 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001513 return 1;
1514 }
1515 }
1516
Radek Krejciba5cec62016-03-24 10:40:29 +01001517 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001518 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001519 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01001520 return -1;
1521 }
1522
1523 return 0;
Radek Krejciba5cec62016-03-24 10:40:29 +01001524
1525error:
1526 ly_set_free(keys);
1527 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001528}
1529
1530struct lyd_node *
1531resolve_partial_json_data_nodeid(const char *nodeid, struct lyd_node *start, int *parsed)
1532{
Radek Krejcib3ecac22016-03-24 10:35:43 +01001533 char module_name[LY_MODULE_NAME_MAX_LEN + 1];
Michal Vasko22448d32016-03-16 13:17:29 +01001534 const char *id, *mod_name, *name;
1535 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001536 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko22448d32016-03-16 13:17:29 +01001537 const struct lys_module *prefix_mod, *prev_mod;
1538 struct ly_ctx *ctx;
1539
1540 assert(nodeid && start && parsed);
1541
1542 ctx = start->schema->module->ctx;
1543 id = nodeid;
1544
1545 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 +01001546 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001547 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001548 return NULL;
1549 }
1550 id += r;
1551 /* add it to parsed only after the data node was actually found */
1552 last_parsed = r;
1553
1554 if (is_relative) {
1555 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01001556 start = start->child;
1557 } else {
1558 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01001559 prev_mod = start->schema->module;
1560 }
1561
1562 while (1) {
1563 LY_TREE_FOR(start, sibling) {
1564 /* name match */
1565 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
1566
1567 /* module check */
1568 if (mod_name) {
1569 if (mod_name_len > LY_MODULE_NAME_MAX_LEN) {
1570 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001571 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001572 return NULL;
1573 }
1574 strncpy(module_name, mod_name, mod_name_len);
1575 module_name[mod_name_len] = '\0';
1576 /* will also find an augment module */
1577 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
1578 if (!prefix_mod) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001579 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001580 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001581 return NULL;
1582 }
1583 } else {
1584 prefix_mod = prev_mod;
1585 }
1586 if (prefix_mod != lys_node_module(sibling->schema)) {
1587 continue;
1588 }
1589
1590 /* leaf-list never matches, it does not make sense */
1591 if (sibling->schema->nodetype == LYS_LEAFLIST) {
1592 sibling = NULL;
1593 break;
1594 }
1595
1596 /* is it a list? we need predicates'n'stuff then */
1597 if (sibling->schema->nodetype == LYS_LIST) {
1598 r = 0;
1599 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001600 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001601 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001602 return NULL;
1603 }
1604 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
1605 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01001606 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001607 return NULL;
1608 } else if (ret == 1) {
1609 /* this list instance does not match */
1610 continue;
1611 }
1612 id += r;
1613 last_parsed += r;
1614 }
1615
1616 *parsed += last_parsed;
1617
1618 /* the result node? */
1619 if (!id[0]) {
1620 return sibling;
1621 }
1622
1623 /* move down the tree, if possible */
1624 if (start->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001625 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001626 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001627 return NULL;
1628 }
1629 last_match = start;
1630 start = sibling->child;
1631 if (start) {
1632 prev_mod = start->schema->module;
1633 }
1634 break;
1635 }
1636 }
1637
1638 /* no match, return last match */
1639 if (!sibling) {
1640 return last_match;
1641 }
1642
1643 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 +01001644 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001645 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001646 return NULL;
1647 }
1648 id += r;
1649 last_parsed = r;
1650 }
1651
1652 /* cannot get here */
1653 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001654 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001655 return NULL;
1656}
1657
Michal Vasko3edeaf72016-02-11 13:17:43 +01001658/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001659 * @brief Resolves length or range intervals. Does not log.
1660 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1661 *
1662 * @param[in] str_restr The restriction as a string.
1663 * @param[in] type The type of the restriction.
1664 * @param[in] superior_restr Flag whether to check superior
1665 * types.
1666 * @param[out] local_intv The final interval structure.
1667 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001668 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001669 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001670int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001671resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1672 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001673{
1674 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001675 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001676 int64_t local_smin, local_smax;
1677 uint64_t local_umin, local_umax;
1678 long double local_fmin, local_fmax;
1679 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001680 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001681
1682 switch (type->base) {
1683 case LY_TYPE_BINARY:
1684 kind = 0;
1685 local_umin = 0;
1686 local_umax = 18446744073709551615UL;
1687
1688 if (!str_restr && type->info.binary.length) {
1689 str_restr = type->info.binary.length->expr;
1690 }
1691 break;
1692 case LY_TYPE_DEC64:
1693 kind = 2;
1694 local_fmin = -9223372036854775808.0;
1695 local_fmin /= 1 << type->info.dec64.dig;
1696 local_fmax = 9223372036854775807.0;
1697 local_fmax /= 1 << type->info.dec64.dig;
1698
1699 if (!str_restr && type->info.dec64.range) {
1700 str_restr = type->info.dec64.range->expr;
1701 }
1702 break;
1703 case LY_TYPE_INT8:
1704 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001705 local_smin = __INT64_C(-128);
1706 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001707
1708 if (!str_restr && type->info.num.range) {
1709 str_restr = type->info.num.range->expr;
1710 }
1711 break;
1712 case LY_TYPE_INT16:
1713 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001714 local_smin = __INT64_C(-32768);
1715 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001716
1717 if (!str_restr && type->info.num.range) {
1718 str_restr = type->info.num.range->expr;
1719 }
1720 break;
1721 case LY_TYPE_INT32:
1722 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001723 local_smin = __INT64_C(-2147483648);
1724 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001725
1726 if (!str_restr && type->info.num.range) {
1727 str_restr = type->info.num.range->expr;
1728 }
1729 break;
1730 case LY_TYPE_INT64:
1731 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001732 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1733 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001734
1735 if (!str_restr && type->info.num.range) {
1736 str_restr = type->info.num.range->expr;
1737 }
1738 break;
1739 case LY_TYPE_UINT8:
1740 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001741 local_umin = __UINT64_C(0);
1742 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001743
1744 if (!str_restr && type->info.num.range) {
1745 str_restr = type->info.num.range->expr;
1746 }
1747 break;
1748 case LY_TYPE_UINT16:
1749 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001750 local_umin = __UINT64_C(0);
1751 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001752
1753 if (!str_restr && type->info.num.range) {
1754 str_restr = type->info.num.range->expr;
1755 }
1756 break;
1757 case LY_TYPE_UINT32:
1758 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001759 local_umin = __UINT64_C(0);
1760 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001761
1762 if (!str_restr && type->info.num.range) {
1763 str_restr = type->info.num.range->expr;
1764 }
1765 break;
1766 case LY_TYPE_UINT64:
1767 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001768 local_umin = __UINT64_C(0);
1769 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001770
1771 if (!str_restr && type->info.num.range) {
1772 str_restr = type->info.num.range->expr;
1773 }
1774 break;
1775 case LY_TYPE_STRING:
1776 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001777 local_umin = __UINT64_C(0);
1778 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001779
1780 if (!str_restr && type->info.str.length) {
1781 str_restr = type->info.str.length->expr;
1782 }
1783 break;
1784 default:
1785 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001786 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001787 }
1788
1789 /* process superior types */
1790 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001791 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1792 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001793 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001794 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001795 assert(!intv || (intv->kind == kind));
1796 }
1797
1798 if (!str_restr) {
1799 /* we are validating data and not have any restriction, but a superior type might have */
1800 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001801 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1802 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001803 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001804 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001805 assert(!intv || (intv->kind == kind));
1806 }
1807 *local_intv = intv;
1808 return EXIT_SUCCESS;
1809 }
1810
1811 /* adjust local min and max */
1812 if (intv) {
1813 tmp_intv = intv;
1814
1815 if (kind == 0) {
1816 local_umin = tmp_intv->value.uval.min;
1817 } else if (kind == 1) {
1818 local_smin = tmp_intv->value.sval.min;
1819 } else if (kind == 2) {
1820 local_fmin = tmp_intv->value.fval.min;
1821 }
1822
1823 while (tmp_intv->next) {
1824 tmp_intv = tmp_intv->next;
1825 }
1826
1827 if (kind == 0) {
1828 local_umax = tmp_intv->value.uval.max;
1829 } else if (kind == 1) {
1830 local_smax = tmp_intv->value.sval.max;
1831 } else if (kind == 2) {
1832 local_fmax = tmp_intv->value.fval.max;
1833 }
1834 }
1835
1836 /* finally parse our restriction */
1837 seg_ptr = str_restr;
1838 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001839 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001840 *local_intv = malloc(sizeof **local_intv);
1841 tmp_local_intv = *local_intv;
1842 } else {
1843 tmp_local_intv->next = malloc(sizeof **local_intv);
1844 tmp_local_intv = tmp_local_intv->next;
1845 }
Michal Vasko253035f2015-12-17 16:58:13 +01001846 if (!tmp_local_intv) {
1847 LOGMEM;
1848 return -1;
1849 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001850
1851 tmp_local_intv->kind = kind;
1852 tmp_local_intv->next = NULL;
1853
1854 /* min */
1855 ptr = seg_ptr;
1856 while (isspace(ptr[0])) {
1857 ++ptr;
1858 }
1859 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1860 if (kind == 0) {
1861 tmp_local_intv->value.uval.min = atoll(ptr);
1862 } else if (kind == 1) {
1863 tmp_local_intv->value.sval.min = atoll(ptr);
1864 } else if (kind == 2) {
1865 tmp_local_intv->value.fval.min = atoll(ptr);
1866 }
1867
1868 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1869 ++ptr;
1870 }
1871 while (isdigit(ptr[0])) {
1872 ++ptr;
1873 }
1874 } else if (!strncmp(ptr, "min", 3)) {
1875 if (kind == 0) {
1876 tmp_local_intv->value.uval.min = local_umin;
1877 } else if (kind == 1) {
1878 tmp_local_intv->value.sval.min = local_smin;
1879 } else if (kind == 2) {
1880 tmp_local_intv->value.fval.min = local_fmin;
1881 }
1882
1883 ptr += 3;
1884 } else if (!strncmp(ptr, "max", 3)) {
1885 if (kind == 0) {
1886 tmp_local_intv->value.uval.min = local_umax;
1887 } else if (kind == 1) {
1888 tmp_local_intv->value.sval.min = local_smax;
1889 } else if (kind == 2) {
1890 tmp_local_intv->value.fval.min = local_fmax;
1891 }
1892
1893 ptr += 3;
1894 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001895 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001896 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001897 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001898 }
1899
1900 while (isspace(ptr[0])) {
1901 ptr++;
1902 }
1903
1904 /* no interval or interval */
1905 if ((ptr[0] == '|') || !ptr[0]) {
1906 if (kind == 0) {
1907 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1908 } else if (kind == 1) {
1909 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1910 } else if (kind == 2) {
1911 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1912 }
1913 } else if (!strncmp(ptr, "..", 2)) {
1914 /* skip ".." */
1915 ptr += 2;
1916 while (isspace(ptr[0])) {
1917 ++ptr;
1918 }
1919
1920 /* max */
1921 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1922 if (kind == 0) {
1923 tmp_local_intv->value.uval.max = atoll(ptr);
1924 } else if (kind == 1) {
1925 tmp_local_intv->value.sval.max = atoll(ptr);
1926 } else if (kind == 2) {
1927 tmp_local_intv->value.fval.max = atoll(ptr);
1928 }
1929 } else if (!strncmp(ptr, "max", 3)) {
1930 if (kind == 0) {
1931 tmp_local_intv->value.uval.max = local_umax;
1932 } else if (kind == 1) {
1933 tmp_local_intv->value.sval.max = local_smax;
1934 } else if (kind == 2) {
1935 tmp_local_intv->value.fval.max = local_fmax;
1936 }
1937 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001938 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001939 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001940 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001941 }
1942 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001943 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001944 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001945 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001946 }
1947
1948 /* next segment (next OR) */
1949 seg_ptr = strchr(seg_ptr, '|');
1950 if (!seg_ptr) {
1951 break;
1952 }
1953 seg_ptr++;
1954 }
1955
1956 /* check local restrictions against superior ones */
1957 if (intv) {
1958 tmp_intv = intv;
1959 tmp_local_intv = *local_intv;
1960
1961 while (tmp_local_intv && tmp_intv) {
1962 /* reuse local variables */
1963 if (kind == 0) {
1964 local_umin = tmp_local_intv->value.uval.min;
1965 local_umax = tmp_local_intv->value.uval.max;
1966
1967 /* it must be in this interval */
1968 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1969 /* this interval is covered, next one */
1970 if (local_umax <= tmp_intv->value.uval.max) {
1971 tmp_local_intv = tmp_local_intv->next;
1972 continue;
1973 /* ascending order of restrictions -> fail */
1974 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001975 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001976 goto cleanup;
1977 }
1978 }
1979 } else if (kind == 1) {
1980 local_smin = tmp_local_intv->value.sval.min;
1981 local_smax = tmp_local_intv->value.sval.max;
1982
1983 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1984 if (local_smax <= tmp_intv->value.sval.max) {
1985 tmp_local_intv = tmp_local_intv->next;
1986 continue;
1987 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001988 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001989 goto cleanup;
1990 }
1991 }
1992 } else if (kind == 2) {
1993 local_fmin = tmp_local_intv->value.fval.min;
1994 local_fmax = tmp_local_intv->value.fval.max;
1995
1996 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1997 if (local_fmax <= tmp_intv->value.fval.max) {
1998 tmp_local_intv = tmp_local_intv->next;
1999 continue;
2000 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002001 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002002 goto cleanup;
2003 }
2004 }
2005 }
2006
2007 tmp_intv = tmp_intv->next;
2008 }
2009
2010 /* some interval left uncovered -> fail */
2011 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002012 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002013 }
2014
2015 }
2016
2017cleanup:
2018 while (intv) {
2019 tmp_intv = intv->next;
2020 free(intv);
2021 intv = tmp_intv;
2022 }
2023
2024 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002025 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002026 while (*local_intv) {
2027 tmp_local_intv = (*local_intv)->next;
2028 free(*local_intv);
2029 *local_intv = tmp_local_intv;
2030 }
2031 }
2032
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002033 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002034}
2035
Michal Vasko730dfdf2015-08-11 14:48:05 +02002036/**
Michal Vasko88c29542015-11-27 14:57:53 +01002037 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002038 *
2039 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002040 * @param[in] mod_name Typedef name module name.
2041 * @param[in] module Main module.
2042 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002043 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002044 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002045 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002046 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002047int
Michal Vasko1e62a092015-12-01 12:27:20 +01002048resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2049 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002050{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002051 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002052 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002053 int tpdf_size;
2054
Michal Vasko1dca6882015-10-22 14:29:42 +02002055 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002056 /* no prefix, try built-in types */
2057 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2058 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002059 if (ret) {
2060 *ret = ly_types[i].def;
2061 }
2062 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002063 }
2064 }
2065 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002066 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002067 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002068 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002069 }
2070 }
2071
Michal Vasko1dca6882015-10-22 14:29:42 +02002072 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002073 /* search in local typedefs */
2074 while (parent) {
2075 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002076 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002077 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2078 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002079 break;
2080
Radek Krejci76512572015-08-04 09:47:08 +02002081 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002082 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2083 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002084 break;
2085
Radek Krejci76512572015-08-04 09:47:08 +02002086 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002087 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2088 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002089 break;
2090
Radek Krejci76512572015-08-04 09:47:08 +02002091 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02002092 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
2093 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002094 break;
2095
Radek Krejci76512572015-08-04 09:47:08 +02002096 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002097 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2098 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002099 break;
2100
Radek Krejci76512572015-08-04 09:47:08 +02002101 case LYS_INPUT:
2102 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02002103 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
2104 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002105 break;
2106
2107 default:
2108 parent = parent->parent;
2109 continue;
2110 }
2111
2112 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002113 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002114 if (ret) {
2115 *ret = &tpdf[i];
2116 }
2117 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002118 }
2119 }
2120
2121 parent = parent->parent;
2122 }
Radek Krejcic071c542016-01-27 14:57:51 +01002123 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002124 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002125 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002126 if (!module) {
2127 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002128 }
2129 }
2130
2131 /* search in top level typedefs */
2132 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002133 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002134 if (ret) {
2135 *ret = &module->tpdf[i];
2136 }
2137 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002138 }
2139 }
2140
2141 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002142 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002143 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002144 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002145 if (ret) {
2146 *ret = &module->inc[i].submodule->tpdf[j];
2147 }
2148 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002149 }
2150 }
2151 }
2152
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002153 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002154}
2155
Michal Vasko1dca6882015-10-22 14:29:42 +02002156/**
2157 * @brief Check the default \p value of the \p type. Logs directly.
2158 *
2159 * @param[in] type Type definition to use.
2160 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002161 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002162 *
2163 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2164 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002165static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002166check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002167{
Michal Vasko1dca6882015-10-22 14:29:42 +02002168 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002169 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002170
2171 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002172 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002173 node.value_str = value;
2174 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002175 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002176 if (!node.schema) {
2177 LOGMEM;
2178 return -1;
2179 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002180 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01002181 if (!node.schema->name) {
2182 LOGMEM;
2183 return -1;
2184 }
Michal Vasko56826402016-03-02 11:11:37 +01002185 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002186 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002187
Radek Krejci37b756f2016-01-18 10:15:03 +01002188 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002189 if (!type->info.lref.target) {
2190 ret = EXIT_FAILURE;
2191 goto finish;
2192 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002193 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002194
2195 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2196 /* it was converted to JSON format before, nothing else sensible we can do */
2197
2198 } else {
Radek Krejci0b7704f2016-03-18 12:16:14 +01002199 ret = lyp_parse_value(&node, NULL, 1);
Michal Vasko1dca6882015-10-22 14:29:42 +02002200 }
2201
2202finish:
2203 if (node.value_type == LY_TYPE_BITS) {
2204 free(node.value.bit);
2205 }
2206 free((char *)node.schema->name);
2207 free(node.schema);
2208
2209 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002210}
2211
Michal Vasko730dfdf2015-08-11 14:48:05 +02002212/**
2213 * @brief Check a key for mandatory attributes. Logs directly.
2214 *
2215 * @param[in] key The key to check.
2216 * @param[in] flags What flags to check.
2217 * @param[in] list The list of all the keys.
2218 * @param[in] index Index of the key in the key list.
2219 * @param[in] name The name of the keys.
2220 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002221 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002222 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002223 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002225check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002226{
Radek Krejciadb57612016-02-16 13:34:34 +01002227 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002228 char *dup = NULL;
2229 int j;
2230
2231 /* existence */
2232 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002233 if (name[len] != '\0') {
2234 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002235 if (!dup) {
2236 LOGMEM;
2237 return -1;
2238 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002239 dup[len] = '\0';
2240 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002241 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002242 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002243 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002244 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002245 }
2246
2247 /* uniqueness */
2248 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002249 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002250 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002251 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002252 }
2253 }
2254
2255 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002256 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002257 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002258 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002259 }
2260
2261 /* type of the leaf is not built-in empty */
2262 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002263 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002264 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002265 }
2266
2267 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002268 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002269 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002270 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002271 }
2272
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002273 /* key is not placed from augment */
2274 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002275 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
2276 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002277 return -1;
2278 }
2279
Michal Vaskocca47842016-03-17 10:31:07 +01002280 /* key is not when-conditional */
2281 if (key->when) {
Radek Krejci02a04992016-03-17 16:06:37 +01002282 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
2283 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
Radek Krejci581ce772015-11-10 17:22:40 +01002284 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002285 }
2286
Michal Vasko0b85aa82016-03-07 14:37:43 +01002287 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02002288}
Michal Vasko730dfdf2015-08-11 14:48:05 +02002289
2290/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002291 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002292 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002293 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002294 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002295 *
2296 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
2297 */
2298int
Radek Krejci48464ed2016-03-17 15:44:09 +01002299resolve_unique(struct lys_node *parent, const char *uniq_str_path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002300{
Radek Krejci581ce772015-11-10 17:22:40 +01002301 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002302 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002303
Michal Vasko0b85aa82016-03-07 14:37:43 +01002304 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002305 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002306 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002307 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002308 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002309 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejci581ce772015-11-10 17:22:40 +01002310 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002311 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01002312 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01002313 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2314 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002315 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002316 }
Radek Krejci581ce772015-11-10 17:22:40 +01002317 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002318 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002319 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002320 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2321 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002322 rc = -1;
2323 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002324 }
2325
Radek Krejcicf509982015-12-15 09:22:44 +01002326 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01002327 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002328 return -1;
2329 }
2330
Radek Krejcica7efb72016-01-18 13:06:01 +01002331 /* set leaf's unique flag */
2332 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2333
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002334 return EXIT_SUCCESS;
2335
2336error:
2337
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002338 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002339}
2340
Michal Vasko730dfdf2015-08-11 14:48:05 +02002341/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002342 * @brief Resolve (find) a feature definition. Logs directly.
2343 *
2344 * @param[in] name Feature name.
2345 * @param[in] module Module to search in.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002346 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002347 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002348 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002349 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002350static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002351resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002352{
Michal Vasko2d851a92015-10-20 16:16:36 +02002353 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002354 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002355 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002356
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002357 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002358 assert(module);
2359
2360 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002361 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002362 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002363 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002364 }
2365
Radek Krejcic071c542016-01-27 14:57:51 +01002366 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2367 if (!module) {
2368 /* identity refers unknown data model */
Radek Krejci48464ed2016-03-17 15:44:09 +01002369 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002370 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002371 }
2372
Radek Krejcic071c542016-01-27 14:57:51 +01002373 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002374 for (j = 0; j < module->features_size; j++) {
2375 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002376 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002377 /* check status */
2378 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002379 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejci48464ed2016-03-17 15:44:09 +01002380 module->features[j].module, module->features[j].name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002381 return -1;
2382 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002383 *ret = &module->features[j];
2384 }
2385 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002386 }
2387 }
Radek Krejcic071c542016-01-27 14:57:51 +01002388 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002389 for (i = 0; i < module->inc_size; i++) {
2390 if (!module->inc[i].submodule) {
2391 /* not yet resolved */
2392 continue;
2393 }
Radek Krejcic071c542016-01-27 14:57:51 +01002394 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2395 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2396 if (ret) {
2397 /* check status */
2398 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002399 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002400 module->inc[i].submodule->features[j].flags,
2401 module->inc[i].submodule->features[j].module,
Radek Krejci48464ed2016-03-17 15:44:09 +01002402 module->inc[i].submodule->features[j].name, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002403 return -1;
2404 }
2405 *ret = &(module->inc[i].submodule->features[j]);
2406 }
2407 return EXIT_SUCCESS;
2408 }
2409 }
2410 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002411
2412 /* not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01002413 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002414 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002415}
2416
Radek Krejci0c0086a2016-03-24 15:20:28 +01002417void
Michal Vasko23b61ec2015-08-19 11:19:50 +02002418unres_data_del(struct unres_data *unres, uint32_t i)
2419{
2420 /* there are items after the one deleted */
2421 if (i+1 < unres->count) {
2422 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002423 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002424
2425 /* deleting the last item */
2426 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002427 free(unres->node);
2428 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002429 }
2430
2431 /* if there are no items after and it is not the last one, just move the counter */
2432 --unres->count;
2433}
2434
Michal Vasko0491ab32015-08-19 14:28:29 +02002435/**
2436 * @brief Resolve (find) a data node from a specific module. Does not log.
2437 *
2438 * @param[in] mod Module to search in.
2439 * @param[in] name Name of the data node.
2440 * @param[in] nam_len Length of the name.
2441 * @param[in] start Data node to start the search from.
2442 * @param[in,out] parents Resolved nodes. If there are some parents,
2443 * they are replaced (!!) with the resolvents.
2444 *
2445 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2446 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002447static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002448resolve_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 +02002449{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002450 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002451 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002452 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002453
Michal Vasko23b61ec2015-08-19 11:19:50 +02002454 if (!parents->count) {
2455 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002456 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002457 if (!parents->node) {
2458 LOGMEM;
2459 return EXIT_FAILURE;
2460 }
Michal Vaskocf024702015-10-08 15:01:42 +02002461 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002462 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002463 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002464 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002465 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002466 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002467 continue;
2468 }
2469 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002470 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002471 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2472 && node->schema->name[nam_len] == '\0') {
2473 /* matching target */
2474 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002475 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002476 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002477 flag = 1;
2478 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002479 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002480 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002481 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2482 if (!parents->node) {
2483 return EXIT_FAILURE;
2484 }
Michal Vaskocf024702015-10-08 15:01:42 +02002485 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002486 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002487 }
2488 }
2489 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002490
2491 if (!flag) {
2492 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002493 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002494 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002495 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002496 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002497 }
2498
Michal Vasko0491ab32015-08-19 14:28:29 +02002499 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002500}
2501
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002502/**
2503 * @brief Resolve (find) a data node. Does not log.
2504 *
Radek Krejci581ce772015-11-10 17:22:40 +01002505 * @param[in] mod_name Module name of the data node.
2506 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002507 * @param[in] name Name of the data node.
2508 * @param[in] nam_len Length of the name.
2509 * @param[in] start Data node to start the search from.
2510 * @param[in,out] parents Resolved nodes. If there are some parents,
2511 * they are replaced (!!) with the resolvents.
2512 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002513 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002514 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002515static int
Radek Krejci581ce772015-11-10 17:22:40 +01002516resolve_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 +02002517 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002518{
Michal Vasko1e62a092015-12-01 12:27:20 +01002519 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002520 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002521
Michal Vasko23b61ec2015-08-19 11:19:50 +02002522 assert(start);
2523
Michal Vasko31fc3672015-10-21 12:08:13 +02002524 if (mod_name) {
2525 /* we have mod_name, find appropriate module */
2526 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002527 if (!str) {
2528 LOGMEM;
2529 return -1;
2530 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002531 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2532 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002533 if (!mod) {
2534 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002535 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002536 }
2537 } else {
2538 /* no prefix, module is the same as of current node */
2539 mod = start->schema->module;
2540 }
2541
2542 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002543}
2544
Michal Vasko730dfdf2015-08-11 14:48:05 +02002545/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002546 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01002547 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002548 *
Michal Vaskobb211122015-08-19 14:03:11 +02002549 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002550 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002551 * @param[in,out] node_match Nodes satisfying the restriction
2552 * without the predicate. Nodes not
2553 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002554 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002555 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002556 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002557 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002558static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002559resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01002560 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002561{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002562 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002563 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002564 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002565 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2566 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002567 uint32_t j;
2568
2569 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002570 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002571 if (!source_match.node) {
2572 LOGMEM;
2573 return -1;
2574 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002575 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002576 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002577 if (!dest_match.node) {
2578 LOGMEM;
2579 return -1;
2580 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002581
2582 do {
2583 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2584 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002585 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002586 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002587 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002588 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002589 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002590 pred += i;
2591
Michal Vasko23b61ec2015-08-19 11:19:50 +02002592 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002593 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002594 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002595
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002596 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002597 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002598 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002599 i = 0;
2600 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002601 }
2602
2603 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002604 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002605 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002606 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2607 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002608 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002609 rc = -1;
2610 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002611 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002612 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002613 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002614 dest_match.node[0] = dest_match.node[0]->parent;
2615 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002616 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002617 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002618 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002619 }
2620 }
2621 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002622 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002623 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002624 i = 0;
2625 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002626 }
2627
2628 if (pke_len == pke_parsed) {
2629 break;
2630 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002631 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 +02002632 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002633 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002634 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002635 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002636 }
2637 pke_parsed += i;
2638 }
2639
2640 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002641 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2642 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002643 goto remove_leafref;
2644 }
2645
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002646 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002647 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002648 goto remove_leafref;
2649 }
2650
2651 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002652 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002653 continue;
2654
2655remove_leafref:
2656 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002657 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002658 }
2659 } while (has_predicate);
2660
Michal Vaskocf024702015-10-08 15:01:42 +02002661 free(source_match.node);
2662 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002663 if (parsed) {
2664 *parsed = parsed_loc;
2665 }
2666 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002667
2668error:
2669
2670 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002671 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002672 }
2673 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002674 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002675 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002676 if (parsed) {
2677 *parsed = -parsed_loc+i;
2678 }
2679 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002680}
2681
Michal Vasko730dfdf2015-08-11 14:48:05 +02002682/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002683 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002684 *
Michal Vaskocf024702015-10-08 15:01:42 +02002685 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002686 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01002687 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002688 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002689 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002690 */
Michal Vasko184521f2015-09-24 13:14:26 +02002691static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002692resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002693{
Radek Krejci71b795b2015-08-10 16:20:39 +02002694 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002695 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002696 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002697 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002698
Michal Vaskocf024702015-10-08 15:01:42 +02002699 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002700
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002701 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002702 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002703
2704 /* searching for nodeset */
2705 do {
2706 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002707 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002708 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002709 goto error;
2710 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002711 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002712 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002713
Michal Vasko23b61ec2015-08-19 11:19:50 +02002714 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002715 if (parent_times != -1) {
2716 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002717 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002718 if (!ret->node) {
2719 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002720 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002721 goto error;
2722 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002723 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002724 for (i = 0; i < parent_times; ++i) {
2725 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002726 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002727 /* error, too many .. */
Radek Krejci48464ed2016-03-17 15:44:09 +01002728 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002729 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002730 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002731 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002732 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002733 data = ret->node[0] = node->parent;
2734 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002735 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002736 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002737 free(ret->node);
2738 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002739 } else {
2740 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002741 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002742 }
2743 }
2744
2745 /* absolute path */
2746 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002747 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002748 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002749 if (data->prev) {
2750 for (; data->prev->next; data = data->prev);
2751 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002752 }
2753 }
2754
2755 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002756 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002757 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002758 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002759 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002760 goto error;
2761 }
2762
2763 if (has_predicate) {
2764 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002765 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002766 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2767 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002768 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002769 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002770 continue;
2771 }
2772
2773 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002774 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002775 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002776 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002777 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002778 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002779 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780 goto error;
2781 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002782 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002783 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784
Michal Vasko23b61ec2015-08-19 11:19:50 +02002785 if (!ret->count) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002786 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path-parsed);
Michal Vasko0491ab32015-08-19 14:28:29 +02002787 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002788 goto error;
2789 }
2790 }
2791 } while (path[0] != '\0');
2792
Michal Vaskof02e3742015-08-05 16:27:02 +02002793 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002794
2795error:
2796
Michal Vaskocf024702015-10-08 15:01:42 +02002797 free(ret->node);
2798 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002799 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800
Michal Vasko0491ab32015-08-19 14:28:29 +02002801 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002802}
2803
Michal Vasko730dfdf2015-08-11 14:48:05 +02002804/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002805 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002806 *
Michal Vaskobb211122015-08-19 14:03:11 +02002807 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002808 * @param[in] context_node Predicate context node (where the predicate is placed).
2809 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02002810 *
Michal Vasko184521f2015-09-24 13:14:26 +02002811 * @return 0 on forward reference, otherwise the number
2812 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002813 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002814 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002815static int
Radek Krejciadb57612016-02-16 13:34:34 +01002816resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01002817 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02002818{
Michal Vasko1e62a092015-12-01 12:27:20 +01002819 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002820 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2821 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 +02002822 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002823
2824 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002825 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002826 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002827 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002828 return -parsed+i;
2829 }
2830 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002831 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002832
Michal Vasko58090902015-08-13 14:04:15 +02002833 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002834 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002835 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002836 }
Radek Krejciadb57612016-02-16 13:34:34 +01002837 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002838 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002839 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002840 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002841 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002842 }
2843 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002844 }
2845
2846 /* destination */
2847 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2848 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002849 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 +02002850 return -parsed;
2851 }
2852 pke_parsed += i;
2853
Radek Krejciadb57612016-02-16 13:34:34 +01002854 /* parent is actually the parent of this leaf, so skip the first ".." */
2855 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002856 if (!dst_node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002857 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002858 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002859 }
Radek Krejciadb57612016-02-16 13:34:34 +01002860 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002861 }
2862 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002863 if (!dest_pref) {
2864 dest_pref = dst_node->module->name;
2865 }
2866 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002867 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002868 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002869 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002870 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002871 }
2872 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002873 }
2874
2875 if (pke_len == pke_parsed) {
2876 break;
2877 }
2878
2879 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2880 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002881 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01002882 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002883 return -parsed;
2884 }
2885 pke_parsed += i;
2886 }
2887
2888 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002889 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002890 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
2891 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
2892 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02002893 return -parsed;
2894 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002895 } while (has_predicate);
2896
2897 return parsed;
2898}
2899
Michal Vasko730dfdf2015-08-11 14:48:05 +02002900/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002901 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002902 *
Michal Vaskobb211122015-08-19 14:03:11 +02002903 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002904 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002905 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2906 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002907 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002908 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002909 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002910 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002911static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002912resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002913 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002914{
Michal Vasko1e62a092015-12-01 12:27:20 +01002915 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002916 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002917 const char *id, *prefix, *name;
2918 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002919 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002920
Michal Vasko184521f2015-09-24 13:14:26 +02002921 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002922 parent_times = 0;
2923 id = path;
2924
2925 do {
2926 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002927 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 +02002928 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002929 }
2930 id += i;
2931
Michal Vasko184521f2015-09-24 13:14:26 +02002932 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002933 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002934 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002935 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002936 /* get start node */
2937 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002938 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002939 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002940 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002941 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002942 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002943 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002944 if (parent_tpdf) {
2945 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejci48464ed2016-03-17 15:44:09 +01002946 LOGVAL(LYE_NORESOLV, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002947 return -1;
2948 }
2949
Radek Krejciadb57612016-02-16 13:34:34 +01002950 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002951 i = 0;
2952 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002953 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002954 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002955 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002956 }
Michal Vasko58090902015-08-13 14:04:15 +02002957
2958 /* this node is a wrong node, we actually need the augment target */
2959 if (node->nodetype == LYS_AUGMENT) {
2960 node = ((struct lys_node_augment *)node)->target;
2961 if (!node) {
2962 continue;
2963 }
2964 }
2965
2966 ++i;
2967 if (i == parent_times) {
2968 break;
2969 }
2970 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002971 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002972
Michal Vasko1f76a282015-08-04 16:16:53 +02002973 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002974 } else {
2975 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002976 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002977 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002978
Michal Vasko184521f2015-09-24 13:14:26 +02002979 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002980 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002981 /* move down the tree, if possible */
2982 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01002983 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 +01002984 return -1;
2985 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002986 node = node->child;
2987 }
2988
Michal Vasko4f0dad02016-02-15 14:08:23 +01002989 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002990 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01002991 }
2992
Michal Vasko36cbaa42015-12-14 13:15:48 +01002993 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 +02002994 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002995 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002996 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002997 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002998 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002999 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003000
3001 if (has_predicate) {
3002 /* we have predicate, so the current result must be list */
3003 if (node->nodetype != LYS_LIST) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003004 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003005 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003006 }
3007
Radek Krejci48464ed2016-03-17 15:44:09 +01003008 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003009 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003010 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003011 } else if (i < 0) {
3012 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003013 }
3014 id += i;
3015 }
3016 } while (id[0]);
3017
Radek Krejcib1c12512015-08-11 11:22:04 +02003018 /* the target must be leaf or leaf-list */
3019 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003020 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003021 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003022 }
3023
Radek Krejcicf509982015-12-15 09:22:44 +01003024 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003025 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003026 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003027 return -1;
3028 }
3029
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003030 if (ret) {
3031 *ret = node;
3032 }
3033 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003034}
3035
Michal Vasko730dfdf2015-08-11 14:48:05 +02003036/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003037 * @brief Resolve instance-identifier predicate in JSON data format.
3038 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003039 *
Michal Vaskobb211122015-08-19 14:03:11 +02003040 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003041 * @param[in,out] node_match Nodes matching the restriction without
3042 * the predicate. Nodes not satisfying
3043 * the predicate are removed.
3044 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003045 * @return Number of characters successfully parsed,
3046 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003047 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003049resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003051 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003052 struct unres_data target_match;
3053 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003054 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003055 const char *model, *name, *value;
3056 char *str;
3057 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3058 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003059
Michal Vasko1f2cc332015-08-19 11:18:32 +02003060 assert(pred && node_match->count);
3061
Michal Vaskocf024702015-10-08 15:01:42 +02003062 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003063 idx = -1;
3064 parsed = 0;
3065
3066 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003067 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003068 return -parsed+i;
3069 }
3070 parsed += i;
3071 pred += i;
3072
Michal Vasko1f2cc332015-08-19 11:18:32 +02003073 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003074 if (isdigit(name[0])) {
3075 idx = atoi(name);
3076 }
3077
Michal Vasko1f2cc332015-08-19 11:18:32 +02003078 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003079 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003080 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003081 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003082 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003083 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003084 if (!target_match.node) {
3085 LOGMEM;
3086 return -1;
3087 }
Michal Vaskocf024702015-10-08 15:01:42 +02003088 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003089 } else {
3090 str = strndup(model, mod_len);
3091 mod = ly_ctx_get_module(ctx, str, NULL);
3092 free(str);
3093
Radek Krejci804836a2016-02-03 10:39:55 +01003094 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003095 goto remove_instid;
3096 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097 }
3098
3099 /* check that we have the correct type */
3100 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003101 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 goto remove_instid;
3103 }
3104 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003105 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003106 goto remove_instid;
3107 }
3108 }
3109
Michal Vasko83a6c462015-10-08 16:43:53 +02003110 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3111 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003112 || (!value && (idx != cur_idx))) {
3113 goto remove_instid;
3114 }
3115
Michal Vaskocf024702015-10-08 15:01:42 +02003116 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117
3118 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003119 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120 continue;
3121
3122remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003123 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003124
3125 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003126 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127 }
3128 } while (has_predicate);
3129
3130 return parsed;
3131}
3132
Michal Vasko730dfdf2015-08-11 14:48:05 +02003133/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003134 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003135 *
Radek Krejciadb57612016-02-16 13:34:34 +01003136 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003137 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003138 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003139 * @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 +02003140 */
Michal Vasko184521f2015-09-24 13:14:26 +02003141static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003142resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003143{
Radek Krejcic5090c32015-08-12 09:46:19 +02003144 int i = 0, j;
3145 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01003146 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02003147 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003148 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003149 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003150 int mod_len, name_len, has_predicate;
3151 struct unres_data node_match;
3152 uint32_t k;
3153
3154 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155
Radek Krejcic5090c32015-08-12 09:46:19 +02003156 /* we need root to resolve absolute path */
3157 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003158 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003159 if (data->prev) {
3160 for (; data->prev->next; data = data->prev);
3161 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162
Radek Krejcic5090c32015-08-12 09:46:19 +02003163 /* search for the instance node */
3164 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003165 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003166 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003167 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003168 goto error;
3169 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003170 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003171
Michal Vasko1f2cc332015-08-19 11:18:32 +02003172 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003173 if (!str) {
3174 LOGMEM;
3175 goto error;
3176 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003177 mod = ly_ctx_get_module(ctx, str, NULL);
3178 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179
Radek Krejcic5090c32015-08-12 09:46:19 +02003180 if (!mod) {
3181 /* no instance exists */
3182 return NULL;
3183 }
3184
Michal Vasko1f2cc332015-08-19 11:18:32 +02003185 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003186 /* no instance exists */
3187 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188 }
3189
3190 if (has_predicate) {
3191 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003192 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003193 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3194 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3195 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003196 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003197 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003198 continue;
3199 }
3200
3201 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003202 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003204
Michal Vaskof39142b2015-10-21 11:40:05 +02003205 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003206 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003207 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208 goto error;
3209 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003210 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003211
Michal Vasko1f2cc332015-08-19 11:18:32 +02003212 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003213 /* no instance exists */
3214 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003215 }
3216 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 }
3218
Michal Vasko1f2cc332015-08-19 11:18:32 +02003219 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003220 /* no instance exists */
3221 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003222 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003223 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003224 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003225
3226 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003227 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003228
3229 return NULL;
3230 } else {
3231 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003232 result = node_match.node[0];
3233 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003234
3235 return result;
3236 }
3237
3238error:
3239
3240 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003241 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003242
3243 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003244}
3245
Michal Vasko730dfdf2015-08-11 14:48:05 +02003246/**
3247 * @brief Passes config flag down to children. Does not log.
3248 *
3249 * @param[in] node Parent node.
3250 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003251static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003252inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253{
Radek Krejci1d82ef62015-08-07 14:44:40 +02003254 LY_TREE_FOR(node, node) {
3255 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
3256 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 }
3258}
3259
Michal Vasko730dfdf2015-08-11 14:48:05 +02003260/**
Michal Vasko7178e692016-02-12 15:58:05 +01003261 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003262 *
Michal Vaskobb211122015-08-19 14:03:11 +02003263 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003264 * @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 +02003265 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003266 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003267 */
Michal Vasko7178e692016-02-12 15:58:05 +01003268static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003269resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003270{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003271 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003272 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273
Michal Vasko1d87a922015-08-21 12:57:16 +02003274 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275
3276 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003277 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 +01003278 if (rc == -1) {
3279 return -1;
3280 }
3281 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003282 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003283 return -1;
3284 }
3285 if (!aug->target) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003286 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003287 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003288 }
3289
3290 if (!aug->child) {
3291 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003292 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 return EXIT_SUCCESS;
3294 }
3295
Michal Vaskod58d5962016-03-02 14:29:41 +01003296 /* check for mandatory nodes - if the target node is in another module
3297 * the added nodes cannot be mandatory
3298 */
3299 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3300 && lyp_check_mandatory((struct lys_node *)aug)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003301 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
3302 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 +01003303 return -1;
3304 }
3305
Michal Vasko07e89ef2016-03-03 13:28:57 +01003306 /* check augment target type and then augment nodes type */
3307 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3308 LY_TREE_FOR(aug->child, sub) {
3309 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003310 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3311 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003312 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3313 return -1;
3314 }
3315 }
3316 } else if (aug->target->nodetype == LYS_CHOICE) {
3317 LY_TREE_FOR(aug->child, sub) {
3318 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003319 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3320 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003321 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3322 return -1;
3323 }
3324 }
3325 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003326 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3327 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003328 return -1;
3329 }
3330
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003331 /* inherit config information from parent, augment does not have
3332 * config property, but we need to keep the information for subelements
3333 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003334 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003336 inherit_config_flag(sub);
3337 }
3338
Radek Krejcic071c542016-01-27 14:57:51 +01003339 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003340 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01003341 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003342 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003343 }
3344 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003345 /* reconnect augmenting data into the target - add them to the target child list */
3346 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003347 sub = aug->target->child->prev; /* remember current target's last node */
3348 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003349 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003350 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003351 } else {
3352 aug->target->child = aug->child;
3353 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354
3355 return EXIT_SUCCESS;
3356}
3357
Michal Vasko730dfdf2015-08-11 14:48:05 +02003358/**
3359 * @brief Resolve uses, apply augments, refines. Logs directly.
3360 *
Michal Vaskobb211122015-08-19 14:03:11 +02003361 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003362 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003363 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003364 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003365 */
Michal Vasko184521f2015-09-24 13:14:26 +02003366static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003367resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003368{
3369 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003370 struct lys_node *node = NULL;
3371 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003372 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003373 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003374 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003375 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003376
Michal Vasko71e1aa82015-08-12 12:17:51 +02003377 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003378 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003379 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003380
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003382 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01003383 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->flags, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01003384 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003385 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3386 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003387 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 }
3390 ctx = uses->module->ctx;
3391
Michal Vaskodef0db12015-10-07 13:22:48 +02003392 /* we managed to copy the grouping, the rest must be possible to resolve */
3393
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003394 /* apply refines */
3395 for (i = 0; i < uses->refine_size; i++) {
3396 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003397 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
3398 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003399 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003400 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003401 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
3403
Radek Krejci1d82ef62015-08-07 14:44:40 +02003404 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003405 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3406 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003407 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003408 }
3409
3410 /* description on any nodetype */
3411 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003412 lydict_remove(ctx, node->dsc);
3413 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003414 }
3415
3416 /* reference on any nodetype */
3417 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003418 lydict_remove(ctx, node->ref);
3419 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003420 }
3421
3422 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003423 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003424 node->flags &= ~LYS_CONFIG_MASK;
3425 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003426 }
3427
3428 /* default value ... */
3429 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003430 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003431 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003432 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3433 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3434 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003436 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3437 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003438 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003439 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003440 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441 }
3442 }
3443 }
3444
3445 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003446 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003447 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003448 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003449 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450
3451 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003452 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 }
3454 }
3455
3456 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003457 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3458 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3459 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460 }
3461
3462 /* min/max-elements on list or leaf-list */
3463 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003464 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003466 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003467 }
3468 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003469 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003471 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003473 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003474 }
3475 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003476 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477 }
3478 }
3479
3480 /* must in leaf, leaf-list, list, container or anyxml */
3481 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003482 switch (node->nodetype) {
3483 case LYS_LEAF:
3484 old_size = &((struct lys_node_leaf *)node)->must_size;
3485 old_must = &((struct lys_node_leaf *)node)->must;
3486 break;
3487 case LYS_LEAFLIST:
3488 old_size = &((struct lys_node_leaflist *)node)->must_size;
3489 old_must = &((struct lys_node_leaflist *)node)->must;
3490 break;
3491 case LYS_LIST:
3492 old_size = &((struct lys_node_list *)node)->must_size;
3493 old_must = &((struct lys_node_list *)node)->must;
3494 break;
3495 case LYS_CONTAINER:
3496 old_size = &((struct lys_node_container *)node)->must_size;
3497 old_must = &((struct lys_node_container *)node)->must;
3498 break;
3499 case LYS_ANYXML:
3500 old_size = &((struct lys_node_anyxml *)node)->must_size;
3501 old_must = &((struct lys_node_anyxml *)node)->must;
3502 break;
3503 default:
3504 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003505 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003506 }
3507
3508 size = *old_size + rfn->must_size;
3509 must = realloc(*old_must, size * sizeof *rfn->must);
3510 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003512 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003513 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003514 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3515 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3516 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3517 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3518 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3519 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 }
3521
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003522 *old_must = must;
3523 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524 }
3525 }
3526
3527 /* apply augments */
3528 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003529 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003530 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003531 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532 }
3533 }
3534
3535 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536}
3537
Michal Vasko730dfdf2015-08-11 14:48:05 +02003538/**
3539 * @brief Resolve base identity recursively. Does not log.
3540 *
3541 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003542 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003543 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003544 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003545 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003546 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003547 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003548static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003549resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003550 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003551{
Michal Vaskof02e3742015-08-05 16:27:02 +02003552 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003553 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003554 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555
Radek Krejcicf509982015-12-15 09:22:44 +01003556 assert(ret);
3557
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 /* search module */
3559 for (i = 0; i < module->ident_size; i++) {
3560 if (!strcmp(basename, module->ident[i].name)) {
3561
3562 if (!ident) {
3563 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003564 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003565 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003566 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 }
3568
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003569 base = &module->ident[i];
3570 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003571 }
3572 }
3573
3574 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003575 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3576 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3577 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003579 if (!ident) {
3580 *ret = &module->inc[j].submodule->ident[i];
3581 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003583
3584 base = &module->inc[j].submodule->ident[i];
3585 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 }
3587 }
3588 }
3589
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003590matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003591 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003592 if (base) {
3593 /* check for circular reference */
3594 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3595 if (ident == base_iter) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003596 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
3597 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003598 return EXIT_FAILURE;
3599 }
3600 }
3601 /* checks done, store the result */
3602 ident->base = base;
3603
3604 /* maintain backlinks to the derived identitise */
3605 while (base) {
3606 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607 if (der) {
3608 der->next = malloc(sizeof *der);
3609 der = der->next;
3610 } else {
3611 ident->base->der = der = malloc(sizeof *der);
3612 }
Michal Vasko253035f2015-12-17 16:58:13 +01003613 if (!der) {
3614 LOGMEM;
3615 return EXIT_FAILURE;
3616 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617 der->next = NULL;
3618 der->ident = ident;
3619
Radek Krejcibabbff82016-02-19 13:31:37 +01003620 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003621 }
Radek Krejcicf509982015-12-15 09:22:44 +01003622 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003623 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003624 }
3625
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003626 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627}
3628
Michal Vasko730dfdf2015-08-11 14:48:05 +02003629/**
3630 * @brief Resolve base identity. Logs directly.
3631 *
3632 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003633 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003634 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003635 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01003636 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003637 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003638 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003639 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003640static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003641resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejci48464ed2016-03-17 15:44:09 +01003642 struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003643{
3644 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003645 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003646 struct lys_ident *target, **ret;
3647 uint8_t flags;
3648 struct lys_module *mod;
3649
3650 assert((ident && !type) || (!ident && type));
3651
3652 if (!type) {
3653 /* have ident to resolve */
3654 ret = &target;
3655 flags = ident->flags;
3656 mod = ident->module;
3657 } else {
3658 /* have type to fill */
3659 ret = &type->info.ident.ref;
3660 flags = type->parent->flags;
3661 mod = type->parent->module;
3662 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003663
3664 /* search for the base identity */
3665 name = strchr(basename, ':');
3666 if (name) {
3667 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003668 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669 name++;
3670
Michal Vasko2d851a92015-10-20 16:16:36 +02003671 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003672 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003673 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003674 }
3675 } else {
3676 name = basename;
3677 }
3678
Radek Krejcic071c542016-01-27 14:57:51 +01003679 /* get module where to search */
3680 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3681 if (!module) {
3682 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01003683 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003684 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003685 }
3686
Radek Krejcic071c542016-01-27 14:57:51 +01003687 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003688 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003689 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003690 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003691 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003692 }
Radek Krejcic071c542016-01-27 14:57:51 +01003693 /* and all its submodules */
3694 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3695 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3696 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003697 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003698 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003699 }
3700 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003701
Radek Krejci02a04992016-03-17 16:06:37 +01003702 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, parent);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003703 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003704
3705success:
3706 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003707 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
3708 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003709 return -1;
3710 }
3711
3712 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003713}
3714
Michal Vasko730dfdf2015-08-11 14:48:05 +02003715/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003716 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003717 *
3718 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003719 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01003720 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003721 *
3722 * @return Pointer to the identity resolvent, NULL on error.
3723 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003724struct lys_ident *
Radek Krejci48464ed2016-03-17 15:44:09 +01003725resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003727 const char *mod_name, *name;
3728 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003729 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003730
Michal Vaskofb0873c2015-08-21 09:00:07 +02003731 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003732 return NULL;
3733 }
3734
Michal Vaskoc633ca02015-08-21 14:03:51 +02003735 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003736 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003737 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003738 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003739 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01003740 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003741 return NULL;
3742 }
3743
Michal Vaskoc633ca02015-08-21 14:03:51 +02003744 if (!strcmp(base->name, name) && (!mod_name
3745 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003746 return base;
3747 }
3748
3749 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003750 if (!strcmp(der->ident->name, name) && (!mod_name
3751 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3752 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003753 /* we have match */
3754 return der->ident;
3755 }
3756 }
3757
Radek Krejci48464ed2016-03-17 15:44:09 +01003758 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003759 return NULL;
3760}
3761
Michal Vasko730dfdf2015-08-11 14:48:05 +02003762/**
Michal Vasko7955b362015-09-04 14:18:15 +02003763 * @brief Resolve (find) choice default case. Does not log.
3764 *
3765 * @param[in] choic Choice to use.
3766 * @param[in] dflt Name of the default case.
3767 *
3768 * @return Pointer to the default node or NULL.
3769 */
3770static struct lys_node *
3771resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3772{
3773 struct lys_node *child, *ret;
3774
3775 LY_TREE_FOR(choic->child, child) {
3776 if (child->nodetype == LYS_USES) {
3777 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3778 if (ret) {
3779 return ret;
3780 }
3781 }
3782
Radek Krejci749190d2016-02-18 16:26:25 +01003783 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003784 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3785 return child;
3786 }
3787 }
3788
3789 return NULL;
3790}
3791
3792/**
Michal Vaskobb211122015-08-19 14:03:11 +02003793 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003794 *
Michal Vaskobb211122015-08-19 14:03:11 +02003795 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003796 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003797 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003798 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003799 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003800static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003801resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003802{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003803 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01003804 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003805
Radek Krejci010e54b2016-03-15 09:40:34 +01003806 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
3807 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
3808 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
3809 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
3810 * LYS_USESGRP flag is used. */
3811 for (par_grp = uses->parent; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = par_grp->parent);
Michal Vaskoe91afce2015-08-12 12:21:00 +02003812
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003814 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3815 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003816 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003817 return -1;
3818 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003819 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003820 return -1;
3821 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003822 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3823 par_grp->nacm++;
3824 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003825 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003826 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003827 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003828 }
3829
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003830 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003831 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3832 par_grp->nacm++;
3833 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003834 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003835 return EXIT_FAILURE;
3836 }
3837
Radek Krejci48464ed2016-03-17 15:44:09 +01003838 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003839 if (!rc) {
3840 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01003841 if (par_grp && (uses->flags & LYS_USESGRP)) {
3842 if (!par_grp->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003843 LOGINT;
3844 return -1;
3845 }
Radek Krejci010e54b2016-03-15 09:40:34 +01003846 par_grp->nacm--;
3847 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003848 }
Radek Krejcicf509982015-12-15 09:22:44 +01003849
3850 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003851 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003852 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003853 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003854 return -1;
3855 }
3856
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003857 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01003858 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
3859 par_grp->nacm++;
3860 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003861 }
3862
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003863 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003864}
3865
Michal Vasko730dfdf2015-08-11 14:48:05 +02003866/**
Michal Vasko9957e592015-08-17 15:04:09 +02003867 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003868 *
Michal Vaskobb211122015-08-19 14:03:11 +02003869 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003870 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003871 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003872 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003873 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003874static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003875resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003876{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003877 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003878 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003879
3880 for (i = 0; i < list->keys_size; ++i) {
3881 /* get the key name */
3882 if ((value = strpbrk(keys_str, " \t\n"))) {
3883 len = value - keys_str;
3884 while (isspace(value[0])) {
3885 value++;
3886 }
3887 } else {
3888 len = strlen(keys_str);
3889 }
3890
Michal Vasko4f0dad02016-02-15 14:08:23 +01003891 rc = lys_get_sibling(list->child, lys_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003892 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003893 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003894 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003895 }
3896 return rc;
3897 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003898
Radek Krejci48464ed2016-03-17 15:44:09 +01003899 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003900 /* check_key logs */
3901 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003902 }
3903
Radek Krejcicf509982015-12-15 09:22:44 +01003904 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003905 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003906 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3907 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003908 return -1;
3909 }
3910
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003911 /* prepare for next iteration */
3912 while (value && isspace(value[0])) {
3913 value++;
3914 }
3915 keys_str = value;
3916 }
3917
Michal Vaskof02e3742015-08-05 16:27:02 +02003918 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003919}
3920
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003921/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003922 * @brief Resolve (check) all must conditions of \p node.
3923 * Logs directly.
3924 *
3925 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02003926 *
3927 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3928 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003929static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003930resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02003931{
Michal Vaskobf19d252015-10-08 15:39:17 +02003932 uint8_t i, must_size;
3933 struct lys_restr *must;
3934 struct lyxp_set set;
3935
3936 assert(node);
3937 memset(&set, 0, sizeof set);
3938
3939 switch (node->schema->nodetype) {
3940 case LYS_CONTAINER:
3941 must_size = ((struct lys_node_container *)node->schema)->must_size;
3942 must = ((struct lys_node_container *)node->schema)->must;
3943 break;
3944 case LYS_LEAF:
3945 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3946 must = ((struct lys_node_leaf *)node->schema)->must;
3947 break;
3948 case LYS_LEAFLIST:
3949 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3950 must = ((struct lys_node_leaflist *)node->schema)->must;
3951 break;
3952 case LYS_LIST:
3953 must_size = ((struct lys_node_list *)node->schema)->must_size;
3954 must = ((struct lys_node_list *)node->schema)->must;
3955 break;
3956 case LYS_ANYXML:
3957 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3958 must = ((struct lys_node_anyxml *)node->schema)->must;
3959 break;
3960 default:
3961 must_size = 0;
3962 break;
3963 }
3964
3965 for (i = 0; i < must_size; ++i) {
Michal Vasko944a5642016-03-21 11:48:58 +01003966 if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003967 return -1;
3968 }
3969
Michal Vasko944a5642016-03-21 11:48:58 +01003970 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02003971
3972 if (!set.value.bool) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003973 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003974 return 1;
3975 }
3976 }
3977
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003978 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003979}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003980
Michal Vaskobf19d252015-10-08 15:39:17 +02003981/**
Michal Vaskocf024702015-10-08 15:01:42 +02003982 * @brief Resolve (find) when condition context node. Does not log.
3983 *
3984 * @param[in] node Data node, whose conditional definition is being decided.
3985 * @param[in] schema Schema node with a when condition.
3986 *
3987 * @return Context node.
3988 */
3989static struct lyd_node *
3990resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003991{
Michal Vaskocf024702015-10-08 15:01:42 +02003992 struct lyd_node *parent;
3993 struct lys_node *sparent;
3994 uint16_t i, data_depth, schema_depth;
3995
3996 /* find a not schema-only node */
3997 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3998 schema = lys_parent(schema);
3999 if (!schema) {
4000 return NULL;
4001 }
4002 }
4003
4004 /* get node depths */
4005 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
4006 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
4007 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
4008 ++schema_depth;
4009 }
4010 }
4011 if (data_depth < schema_depth) {
4012 return NULL;
4013 }
4014
4015 /* find the corresponding data node */
4016 for (i = 0; i < data_depth - schema_depth; ++i) {
4017 node = node->parent;
4018 }
4019 if (node->schema != schema) {
4020 return NULL;
4021 }
4022
4023 return node;
4024}
4025
Radek Krejci03b71f72016-03-16 11:10:09 +01004026int
Radek Krejci01696bf2016-03-18 13:19:36 +01004027resolve_applies_must(const struct lyd_node *node)
4028{
4029 switch (node->schema->nodetype) {
4030 case LYS_CONTAINER:
4031 return ((struct lys_node_container *)node->schema)->must_size;
4032 case LYS_LEAF:
4033 return ((struct lys_node_leaf *)node->schema)->must_size;
4034 case LYS_LEAFLIST:
4035 return ((struct lys_node_leaflist *)node->schema)->must_size;
4036 case LYS_LIST:
4037 return ((struct lys_node_list *)node->schema)->must_size;
4038 case LYS_ANYXML:
4039 return ((struct lys_node_anyxml *)node->schema)->must_size;
4040 default:
4041 return 0;
4042 }
4043}
4044
4045int
Radek Krejci03b71f72016-03-16 11:10:09 +01004046resolve_applies_when(const struct lyd_node *node)
4047{
4048 struct lys_node *parent;
4049
4050 assert(node);
4051
4052 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
4053 return 1;
4054 }
4055
4056 parent = node->schema;
4057 goto check_augment;
4058
4059 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4060 if (((struct lys_node_uses *)parent)->when) {
4061 return 1;
4062 }
4063check_augment:
4064
4065 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
4066 (((struct lys_node_augment *)parent->parent)->when))) {
4067
4068 }
4069 parent = lys_parent(parent);
4070 }
4071
4072 return 0;
4073}
4074
Michal Vaskocf024702015-10-08 15:01:42 +02004075/**
4076 * @brief Resolve (check) all when conditions relevant for \p node.
4077 * Logs directly.
4078 *
4079 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02004080 *
Radek Krejci03b71f72016-03-16 11:10:09 +01004081 * @return
4082 * -1 - error, ly_errno is set
4083 * 0 - true "when" statement
4084 * 0, ly_vecode = LYVE_NOCOND - false "when" statement
4085 * 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 +02004086 */
4087static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004088resolve_when(struct lyd_node *node)
Michal Vaskocf024702015-10-08 15:01:42 +02004089{
4090 struct lyd_node *ctx_node = NULL;
4091 struct lys_node *parent;
4092 struct lyxp_set set;
Radek Krejci51093642016-03-29 10:14:59 +02004093 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02004094
4095 assert(node);
4096 memset(&set, 0, sizeof set);
4097
4098 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko944a5642016-03-21 11:48:58 +01004099 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004100 if (rc) {
4101 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004102 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004103 }
Radek Krejci51093642016-03-29 10:14:59 +02004104 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004105 }
4106
Radek Krejci03b71f72016-03-16 11:10:09 +01004107 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01004108 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004109 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004110 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004111 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004112 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004113 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004114 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004115 }
Radek Krejci51093642016-03-29 10:14:59 +02004116
4117 /* free xpath set content */
4118 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004119 }
4120
4121 parent = node->schema;
4122 goto check_augment;
4123
4124 /* check when in every schema node that affects node */
4125 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4126 if (((struct lys_node_uses *)parent)->when) {
4127 if (!ctx_node) {
4128 ctx_node = resolve_when_ctx_node(node, parent);
4129 if (!ctx_node) {
4130 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004131 rc = -1;
4132 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004133 }
4134 }
Michal Vasko944a5642016-03-21 11:48:58 +01004135 rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004136 if (rc) {
4137 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004138 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004139 }
Radek Krejci51093642016-03-29 10:14:59 +02004140 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004141 }
4142
Michal Vasko944a5642016-03-21 11:48:58 +01004143 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004144 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004145 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004146 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004147 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004148 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004149 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004150 }
Radek Krejci51093642016-03-29 10:14:59 +02004151
4152 /* free xpath set content */
4153 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004154 }
4155
4156check_augment:
4157 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
4158 if (!ctx_node) {
4159 ctx_node = resolve_when_ctx_node(node, parent->parent);
4160 if (!ctx_node) {
4161 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004162 rc = -1;
4163 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004164 }
4165 }
Michal Vasko944a5642016-03-21 11:48:58 +01004166 rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004167 if (rc) {
4168 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004169 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004170 }
Radek Krejci51093642016-03-29 10:14:59 +02004171 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004172 }
4173
Michal Vasko944a5642016-03-21 11:48:58 +01004174 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004175
4176 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004177 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004178 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004179 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004180 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004181 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004182 }
Radek Krejci51093642016-03-29 10:14:59 +02004183
4184 /* free xpath set content */
4185 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004186 }
4187
4188 parent = lys_parent(parent);
4189 }
4190
Radek Krejci0b7704f2016-03-18 12:16:14 +01004191 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01004192
Radek Krejci51093642016-03-29 10:14:59 +02004193cleanup:
4194
4195 /* free xpath set content */
4196 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
4197
4198 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004199}
4200
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004201/**
Michal Vaskobb211122015-08-19 14:03:11 +02004202 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004203 *
4204 * @param[in] mod Main module.
4205 * @param[in] item Item to resolve. Type determined by \p type.
4206 * @param[in] type Type of the unresolved item.
4207 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02004208 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004209 *
4210 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4211 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004212static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004213resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01004214 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004215{
Radek Krejci4f78b532016-02-17 13:43:00 +01004216 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02004217 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004218 const char *base_name;
4219
4220 struct lys_ident *ident;
4221 struct lys_type *stype;
4222 struct lys_feature **feat_ptr;
4223 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01004224 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004225
4226 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004227 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004228 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004229 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004230 ident = item;
4231
Radek Krejci48464ed2016-03-17 15:44:09 +01004232 rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004233 break;
4234 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004235 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004236 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004237 stype = item;
4238
Radek Krejci48464ed2016-03-17 15:44:09 +01004239 rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004240 break;
4241 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02004242 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004243 stype = item;
4244
Radek Krejci2f12f852016-01-08 12:59:57 +01004245 /* HACK - when there is no parent, we are in top level typedef and in that
4246 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
4247 * know it via tpdf_flag */
4248 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01004249 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01004250 node = (struct lys_node *)stype->parent;
4251 }
4252
Radek Krejci48464ed2016-03-17 15:44:09 +01004253 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01004254 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01004255 if (stype->info.lref.target) {
4256 /* store the backlink from leafref target */
4257 if (!stype->info.lref.target->child) {
4258 stype->info.lref.target->child = (void*)ly_set_new();
4259 if (!stype->info.lref.target->child) {
4260 LOGMEM;
4261 return -1;
4262 }
4263 }
4264 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
4265 }
4266
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004267 break;
4268 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004269 /* parent */
4270 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004271 stype = item;
4272
Michal Vasko88c29542015-11-27 14:57:53 +01004273 /* HACK type->der is temporarily unparsed type statement */
4274 yin = (struct lyxml_elem *)stype->der;
4275 stype->der = NULL;
4276
4277 rc = fill_yin_type(mod, node, yin, stype, unres);
4278 if (!rc) {
4279 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01004280 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01004281 } else {
4282 /* may try again later, put all back how it was */
4283 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004284 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004285 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004286 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004287 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004288 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004289 feat_ptr = item;
4290
Radek Krejci48464ed2016-03-17 15:44:09 +01004291 rc = resolve_feature(base_name, mod, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004292 break;
4293 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004294 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004295 break;
4296 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004297 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004298 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004299 stype = item;
4300
Radek Krejci48464ed2016-03-17 15:44:09 +01004301 rc = check_default(stype, base_name, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004302 break;
4303 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004304 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004305 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004306 choic = item;
4307
Michal Vasko7955b362015-09-04 14:18:15 +02004308 choic->dflt = resolve_choice_dflt(choic, base_name);
4309 if (choic->dflt) {
4310 rc = EXIT_SUCCESS;
4311 } else {
4312 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004313 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004314 break;
4315 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004316 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004317 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318 break;
4319 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004320 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004321 rc = resolve_unique(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004322 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004323 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004324 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01004325 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004326 default:
4327 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004328 break;
4329 }
4330
Radek Krejci4f78b532016-02-17 13:43:00 +01004331 if (has_str && !rc) {
4332 lydict_remove(mod->ctx, str_snode);
4333 }
4334
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004335 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004336}
4337
Michal Vaskof02e3742015-08-05 16:27:02 +02004338/* logs directly */
4339static void
Radek Krejci48464ed2016-03-17 15:44:09 +01004340print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004341{
Michal Vaskof02e3742015-08-05 16:27:02 +02004342 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004343 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004344 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004345 break;
4346 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004347 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004348 break;
4349 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004350 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
4351 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02004352 break;
4353 case UNRES_TYPE_DER:
Radek Krejci48464ed2016-03-17 15:44:09 +01004354 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type",
4355 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value);
Michal Vaskof02e3742015-08-05 16:27:02 +02004356 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004357 case UNRES_IFFEAT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004358 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004359 break;
4360 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004361 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004362 break;
4363 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004364 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004365 break;
4366 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004367 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004368 break;
4369 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01004370 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004371 break;
4372 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01004373 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004374 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004375 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004376 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
4377 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01004378 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004379 default:
4380 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004381 break;
4382 }
4383}
4384
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004385/**
Michal Vaskobb211122015-08-19 14:03:11 +02004386 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004387 *
4388 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004389 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004390 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004391 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004392 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004393int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004394resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004395{
Radek Krejci010e54b2016-03-15 09:40:34 +01004396 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004397 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004398
4399 assert(unres);
4400
Radek Krejci010e54b2016-03-15 09:40:34 +01004401 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4402 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02004403
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004404 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004405 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004406 unres_count = 0;
4407 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004408
4409 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01004410 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
4411 * we need every type's base only */
4412 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004413 continue;
4414 }
4415
Michal Vasko88c29542015-11-27 14:57:53 +01004416 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01004417 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004418 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004419 unres->type[i] = UNRES_RESOLVED;
4420 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004421 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004422 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004423 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004424 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004425 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004426 }
Michal Vasko88c29542015-11-27 14:57:53 +01004427 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004428
Michal Vasko88c29542015-11-27 14:57:53 +01004429 if (res_count < unres_count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004430 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004431 }
4432
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004433 /* the rest */
4434 for (i = 0; i < unres->count; ++i) {
4435 if (unres->type[i] == UNRES_RESOLVED) {
4436 continue;
4437 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004438
Radek Krejci48464ed2016-03-17 15:44:09 +01004439 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004440 if (rc == 0) {
4441 unres->type[i] = UNRES_RESOLVED;
4442 ++resolved;
4443 } else if (rc == -1) {
4444 ly_vlog_hide(0);
Michal Vasko184521f2015-09-24 13:14:26 +02004445 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004446 }
4447 }
4448
Radek Krejci010e54b2016-03-15 09:40:34 +01004449 ly_vlog_hide(0);
4450
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004451 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004452 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
4453 * all the validation errors
4454 */
4455 for (i = 0; i < unres->count; ++i) {
4456 if (unres->type[i] == UNRES_RESOLVED) {
4457 continue;
4458 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004459 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004460 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004461 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004462 }
4463
Radek Krejci010e54b2016-03-15 09:40:34 +01004464 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4465
Radek Krejcic071c542016-01-27 14:57:51 +01004466 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004467 return EXIT_SUCCESS;
4468}
4469
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004470/**
Michal Vaskobb211122015-08-19 14:03:11 +02004471 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004472 *
4473 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004474 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004475 * @param[in] item Item to resolve. Type determined by \p type.
4476 * @param[in] type Type of the unresolved item.
4477 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004478 *
4479 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4480 */
4481int
Radek Krejci48464ed2016-03-17 15:44:09 +01004482unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
4483 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004484{
Radek Krejci48464ed2016-03-17 15:44:09 +01004485 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 +02004486}
4487
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004488/**
Michal Vaskobb211122015-08-19 14:03:11 +02004489 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004490 *
4491 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004492 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004493 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004494 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004495 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004496 *
4497 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4498 */
4499int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004500unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01004501 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004502{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004503 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004504 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01004505 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004506
Michal Vasko9bf425b2015-10-22 11:42:03 +02004507 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4508 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004509
Radek Krejci010e54b2016-03-15 09:40:34 +01004510 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004511 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004512 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004513 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004514 if (rc == -1 && ly_errno == LY_EVALID) {
4515 path = strdup(ly_errpath());
4516 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
4517 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
4518 free(path);
4519 free(msg);
4520 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004521 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004522 }
4523
Radek Krejci48464ed2016-03-17 15:44:09 +01004524 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02004525
Michal Vasko88c29542015-11-27 14:57:53 +01004526 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4527 if (type == UNRES_TYPE_DER) {
4528 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
4529 lyxml_unlink_elem(mod->ctx, yin, 1);
4530 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4531 }
4532
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004533 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004534 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4535 if (!unres->item) {
4536 LOGMEM;
4537 return -1;
4538 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004539 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004540 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4541 if (!unres->type) {
4542 LOGMEM;
4543 return -1;
4544 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004545 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004546 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4547 if (!unres->str_snode) {
4548 LOGMEM;
4549 return -1;
4550 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004551 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004552 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4553 if (!unres->module) {
4554 LOGMEM;
4555 return -1;
4556 }
4557 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004558
4559 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004560}
4561
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004562/**
Michal Vaskobb211122015-08-19 14:03:11 +02004563 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004564 *
4565 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004566 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004567 * @param[in] item Old item to be resolved.
4568 * @param[in] type Type of the old unresolved item.
4569 * @param[in] new_item New item to use in the duplicate.
4570 *
4571 * @return EXIT_SUCCESS on success, -1 on error.
4572 */
Michal Vaskodad19402015-08-06 09:51:53 +02004573int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004574unres_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 +02004575{
4576 int i;
4577
Michal Vaskocf024702015-10-08 15:01:42 +02004578 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004579
Michal Vasko0bd29d12015-08-19 11:45:49 +02004580 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004581
4582 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004583 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004584 }
4585
Michal Vasko0d204592015-10-07 09:50:04 +02004586 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004587 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004588 LOGINT;
4589 return -1;
4590 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004591 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004592 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004593 LOGINT;
4594 return -1;
4595 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004596 }
Michal Vaskodad19402015-08-06 09:51:53 +02004597
4598 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004599}
4600
Michal Vaskof02e3742015-08-05 16:27:02 +02004601/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004602int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004603unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004604{
4605 uint32_t ret = -1, i;
4606
4607 for (i = 0; i < unres->count; ++i) {
4608 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4609 ret = i;
4610 break;
4611 }
4612 }
4613
4614 return ret;
4615}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004616
Michal Vasko88c29542015-11-27 14:57:53 +01004617void
Radek Krejcic071c542016-01-27 14:57:51 +01004618unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004619{
4620 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004621 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01004622
Radek Krejcic071c542016-01-27 14:57:51 +01004623 if (!unres || !(*unres)) {
4624 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004625 }
4626
Radek Krejcic071c542016-01-27 14:57:51 +01004627 assert(module || (*unres)->count == 0);
4628
4629 for (i = 0; i < (*unres)->count; ++i) {
4630 if ((*unres)->module[i] != module) {
4631 if ((*unres)->type[i] != UNRES_RESOLVED) {
4632 unresolved++;
4633 }
4634 continue;
4635 }
4636 if ((*unres)->type[i] == UNRES_TYPE_DER) {
4637 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
4638 }
4639 (*unres)->type[i] = UNRES_RESOLVED;
4640 }
4641
4642 if (!module || (!unresolved && !module->type)) {
4643 free((*unres)->item);
4644 free((*unres)->type);
4645 free((*unres)->str_snode);
4646 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01004647 free((*unres));
4648 (*unres) = NULL;
4649 }
Michal Vasko88c29542015-11-27 14:57:53 +01004650}
4651
Michal Vasko8bcdf292015-08-19 14:04:43 +02004652/**
4653 * @brief Resolve a single unres data item. Logs directly.
4654 *
Michal Vaskocf024702015-10-08 15:01:42 +02004655 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02004656 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004657 *
4658 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4659 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004660int
Radek Krejci48464ed2016-03-17 15:44:09 +01004661resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004662{
4663 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004664 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004665 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004666 struct lys_node_leaf *sleaf;
4667 struct unres_data matches;
4668
4669 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004670 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004671 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004672
Michal Vaskocf024702015-10-08 15:01:42 +02004673 switch (type) {
4674 case UNRES_LEAFREF:
4675 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci48464ed2016-03-17 15:44:09 +01004676 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004677 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004678 }
4679
4680 /* check that value matches */
4681 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004682 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004683 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004684 break;
4685 }
4686 }
4687
Michal Vaskocf024702015-10-08 15:01:42 +02004688 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004689 memset(&matches, 0, sizeof matches);
4690
Michal Vaskocf024702015-10-08 15:01:42 +02004691 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004692 /* reference not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01004693 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
4694 LOGVAL(LYE_SPEC, LY_VLOG_LYD, leaf, "Leafref value \"%s\" did not match any node value.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004695 return EXIT_FAILURE;
4696 }
Michal Vaskocf024702015-10-08 15:01:42 +02004697 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004698
Michal Vaskocf024702015-10-08 15:01:42 +02004699 case UNRES_INSTID:
4700 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004701 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01004702 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01004703 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004704 if (ly_errno) {
4705 return -1;
4706 } else if (sleaf->type.info.inst.req > -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004707 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004708 return EXIT_FAILURE;
4709 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004710 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004711 }
4712 }
Michal Vaskocf024702015-10-08 15:01:42 +02004713 break;
4714
4715 case UNRES_WHEN:
Radek Krejci48464ed2016-03-17 15:44:09 +01004716 if ((rc = resolve_when(node))) {
Michal Vaskocf024702015-10-08 15:01:42 +02004717 return rc;
4718 }
4719 break;
4720
Michal Vaskobf19d252015-10-08 15:39:17 +02004721 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01004722 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004723 return rc;
4724 }
4725 break;
4726
Michal Vaskocf024702015-10-08 15:01:42 +02004727 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004728 LOGINT;
4729 return -1;
4730 }
4731
4732 return EXIT_SUCCESS;
4733}
4734
4735/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01004736 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02004737 *
4738 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004739 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004740 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01004741 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004742 */
4743int
Radek Krejci0b7704f2016-03-18 12:16:14 +01004744unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004745{
Radek Krejci03b71f72016-03-16 11:10:09 +01004746 assert(unres && node);
4747 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004748
Radek Krejci03b71f72016-03-16 11:10:09 +01004749 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004750 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4751 if (!unres->node) {
4752 LOGMEM;
4753 return -1;
4754 }
Michal Vaskocf024702015-10-08 15:01:42 +02004755 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004756 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4757 if (!unres->type) {
4758 LOGMEM;
4759 return -1;
4760 }
Michal Vaskocf024702015-10-08 15:01:42 +02004761 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004762
Radek Krejci0b7704f2016-03-18 12:16:14 +01004763 if (type == UNRES_WHEN) {
4764 /* remove previous result */
4765 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004766 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004767
4768 return EXIT_SUCCESS;
4769}
4770
4771/**
4772 * @brief Resolve every unres data item in the structure. Logs directly.
4773 *
4774 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01004775 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
4776 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01004777 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004778 *
4779 * @return EXIT_SUCCESS on success, -1 on error.
4780 */
4781int
Radek Krejci0c0086a2016-03-24 15:20:28 +01004782resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004783{
Radek Krejci0c0086a2016-03-24 15:20:28 +01004784 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01004785 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01004786 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004787 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004788
Radek Krejci03b71f72016-03-16 11:10:09 +01004789 assert(unres);
4790 assert(root && (*root));
4791
4792 if (!unres->count) {
4793 return EXIT_SUCCESS;
4794 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004795
Radek Krejci010e54b2016-03-15 09:40:34 +01004796 LOGVRB("Resolving unresolved data nodes and their constraints.");
4797 ly_vlog_hide(1);
4798
Radek Krejci0b7704f2016-03-18 12:16:14 +01004799 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01004800 ly_errno = LY_SUCCESS;
4801 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004802 do {
4803 progress = 0;
4804 for(i = 0; i < unres->count; i++) {
4805 if (unres->type[i] != UNRES_WHEN) {
4806 continue;
4807 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004808 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004809 /* count when-stmt nodes in unres list */
4810 when_stmt++;
4811 }
4812
4813 /* resolve when condition only when all parent when conditions are already resolved */
4814 for (parent = unres->node[i]->parent;
4815 parent && LYD_WHEN_DONE(parent->when_status);
4816 parent = parent->parent) {
4817 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
4818 /* the parent node was already unlinked, do not resolve this node,
4819 * it will be removed anyway, so just mark it as resolved
4820 */
4821 unres->node[i]->when_status |= LYD_WHEN_FALSE;
4822 unres->type[i] = UNRES_RESOLVED;
4823 resolved++;
4824 break;
4825 }
4826 }
4827 if (parent) {
4828 continue;
4829 }
Radek Krejci010e54b2016-03-15 09:40:34 +01004830
Radek Krejci48464ed2016-03-17 15:44:09 +01004831 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004832 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004833 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
4834 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004835 /* false when condition */
4836 ly_vlog_hide(0);
4837 path = strdup(ly_errpath());
4838 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
4839 path[0] ? path : "", path[0] ? ")" : "");
4840 free(path);
4841 free(msg);
4842 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004843 } /* follows else */
4844
Radek Krejci0c0086a2016-03-24 15:20:28 +01004845 /* only unlink now, the subtree can contain another nodes stored in the unres list */
4846 /* if it has parent non-presence containers that would be empty, we should actually
4847 * remove the container
4848 */
4849 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
4850 for (parent = unres->node[i];
4851 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
4852 parent = parent->parent) {
4853 if (((struct lys_node_container *)parent->parent->schema)->presence) {
4854 /* presence container */
4855 break;
4856 }
4857 if (parent->next || parent->prev != parent) {
4858 /* non empty (the child we are in and we are going to remove is not the only child) */
4859 break;
4860 }
4861 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004862 unres->node[i] = parent;
4863 }
4864
Radek Krejci0b7704f2016-03-18 12:16:14 +01004865 /* auto-delete */
4866 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
4867 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01004868 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004869 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01004870 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004871
Radek Krejci0b7704f2016-03-18 12:16:14 +01004872 lyd_unlink(unres->node[i]);
4873 unres->type[i] = UNRES_DELETE;
4874 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01004875
4876 /* update the rest of unres items */
4877 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01004878 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01004879 continue;
4880 }
4881
4882 /* test if the node is in subtree to be deleted */
4883 for (parent = unres->node[j]; parent; parent = parent->parent) {
4884 if (parent == unres->node[i]) {
4885 /* yes, it is */
4886 unres->type[j] = UNRES_RESOLVED;
4887 resolved++;
4888 break;
4889 }
4890 }
4891 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004892 } else {
4893 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01004894 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004895 ly_errno = LY_SUCCESS;
4896 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004897 resolved++;
4898 progress = 1;
4899 } else if (rc == -1) {
4900 ly_vlog_hide(0);
4901 return -1;
4902 }
4903 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004904 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004905 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01004906
Radek Krejci0b7704f2016-03-18 12:16:14 +01004907 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01004908 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004909 ly_vlog_hide(0);
4910 path = strdup(ly_errpath());
4911 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
4912 path[0] ? path : "", path[0] ? ")" : "");
4913 free(path);
4914 free(msg);
4915 return -1;
4916 }
4917
4918 for (i = 0; del_items && i < unres->count; i++) {
4919 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
4920 if (unres->type[i] != UNRES_DELETE) {
4921 continue;
4922 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004923 if (!unres->node[i]) {
4924 unres->type[i] = UNRES_RESOLVED;
4925 del_items--;
4926 continue;
4927 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004928
Radek Krejci0b7704f2016-03-18 12:16:14 +01004929 /* really remove the complete subtree */
4930 lyd_free(unres->node[i]);
4931 unres->type[i] = UNRES_RESOLVED;
4932 del_items--;
4933 }
Radek Krejci010e54b2016-03-15 09:40:34 +01004934
4935 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004936 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004937 if (unres->type[i] == UNRES_RESOLVED) {
4938 continue;
4939 }
4940
Radek Krejci48464ed2016-03-17 15:44:09 +01004941 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004942 if (rc == 0) {
4943 unres->type[i] = UNRES_RESOLVED;
4944 resolved++;
4945 } else if (rc == -1) {
4946 ly_vlog_hide(0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004947 return -1;
4948 }
4949 }
4950
Radek Krejci010e54b2016-03-15 09:40:34 +01004951 ly_vlog_hide(0);
4952 if (resolved < unres->count) {
4953 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
4954 * all the validation errors
4955 */
4956 for (i = 0; i < unres->count; ++i) {
4957 if (unres->type[i] == UNRES_RESOLVED) {
4958 continue;
4959 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004960 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004961 }
4962 return -1;
4963 }
4964
4965 LOGVRB("All data nodes and constraints resolved");
4966 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004967 return EXIT_SUCCESS;
4968}