blob: d5f7998ec04b9881e880d0f97943a513abeb6fc1 [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)
753 * descendant-schema-nodeid =
754 * 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.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
761 * @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 }
800 } else {
801 if (*is_relative == -1) {
802 *is_relative = 0;
803 }
804 ++parsed;
805 ++id;
806 }
807
Michal Vasko723e50c2015-10-20 15:20:29 +0200808 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200809 return -parsed+ret;
810 }
811
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100812 parsed += ret;
813 id += ret;
814
815 if ((id[0] == '[') && has_predicate) {
816 *has_predicate = 1;
817 }
818
819 return parsed;
820}
821
822/**
823 * @brief Parse schema predicate (special format internally used).
824 *
825 * predicate = "[" *WSP predicate-expr *WSP "]"
826 * predicate-expr = identifier / key-with-value
827 * key-with-value = identifier *WSP "=" *WSP
828 * ((DQUOTE string DQUOTE) /
829 * (SQUOTE string SQUOTE))
830 *
831 * @param[in] id Identifier to use.
832 * @param[out] name Points to the list key name.
833 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100834 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100835 * @param[out] val_len Length of \p value.
836 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
837 */
Michal Vasko22448d32016-03-16 13:17:29 +0100838int
Michal Vasko3547c532016-03-14 09:40:50 +0100839parse_schema_list_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
840 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100841{
842 const char *ptr;
843 int parsed = 0, ret;
844 char quote;
845
846 assert(id);
847 if (name) {
848 *name = NULL;
849 }
850 if (nam_len) {
851 *nam_len = 0;
852 }
853 if (value) {
854 *value = NULL;
855 }
856 if (val_len) {
857 *val_len = 0;
858 }
859 if (has_predicate) {
860 *has_predicate = 0;
861 }
862
863 if (id[0] != '[') {
864 return -parsed;
865 }
866
867 ++parsed;
868 ++id;
869
870 while (isspace(id[0])) {
871 ++parsed;
872 ++id;
873 }
874
Michal Vasko22448d32016-03-16 13:17:29 +0100875 /* identifier */
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100876 if ((ret = parse_identifier(id)) < 1) {
877 return -parsed + ret;
878 }
879 if (name) {
880 *name = id;
881 }
882 if (nam_len) {
883 *nam_len = ret;
884 }
885
886 parsed += ret;
887 id += ret;
888
889 while (isspace(id[0])) {
890 ++parsed;
891 ++id;
892 }
893
894 /* there is value as well */
895 if (id[0] == '=') {
896 ++parsed;
897 ++id;
898
899 while (isspace(id[0])) {
900 ++parsed;
901 ++id;
902 }
903
904 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
905 if ((id[0] == '\"') || (id[0] == '\'')) {
906 quote = id[0];
907
908 ++parsed;
909 ++id;
910
911 if ((ptr = strchr(id, quote)) == NULL) {
912 return -parsed;
913 }
914 ret = ptr - id;
915
916 if (value) {
917 *value = id;
918 }
919 if (val_len) {
920 *val_len = ret;
921 }
922
923 parsed += ret + 1;
924 id += ret + 1;
925 } else {
926 return -parsed;
927 }
928
929 while (isspace(id[0])) {
930 ++parsed;
931 ++id;
932 }
Michal Vasko22448d32016-03-16 13:17:29 +0100933 } else if (value) {
934 /* if value was expected, it's mandatory */
935 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100936 }
937
938 if (id[0] != ']') {
939 return -parsed;
940 }
941
942 ++parsed;
943 ++id;
944
945 if ((id[0] == '[') && has_predicate) {
946 *has_predicate = 1;
947 }
948
949 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200950}
951
952/**
Michal Vasko3edeaf72016-02-11 13:17:43 +0100953 * @brief Resolve (find) a data node based on a schema-nodeid.
954 *
955 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
956 * module).
957 *
958 */
959struct lyd_node *
960resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
961{
962 char *str, *token, *p;
963 struct lyd_node *result = start, *iter;
964 const struct lys_node *schema = NULL;
965
966 assert(nodeid && start);
967
968 if (nodeid[0] == '/') {
969 return NULL;
970 }
971
972 str = p = strdup(nodeid);
973 if (!str) {
974 LOGMEM;
975 return NULL;
976 }
977 while (p) {
978 token = p;
979 p = strchr(p, '/');
980 if (p) {
981 *p = '\0';
982 p++;
983 }
984
985 schema = NULL;
986 if (resolve_descendant_schema_nodeid(token, result->schema, LYS_LEAF, &schema) || !schema) {
987 free(str);
988 return NULL;
989 }
990
991 LY_TREE_FOR(result, iter) {
992 if (iter->schema == schema) {
993 break;
994 }
995 }
996
997 if (!p) {
998 /* final result */
999 result = iter;
1000 } else {
1001 result = iter->child;
1002 }
1003 }
1004 free(str);
1005
1006 return result;
1007}
1008
1009/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1010int
1011resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1012 const struct lys_node **ret)
1013{
1014 const char *name, *mod_name, *id;
1015 const struct lys_node *sibling;
1016 int r, nam_len, mod_name_len, is_relative = -1;
1017 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001018 const struct lys_module *prefix_mod, *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001019
1020 assert(nodeid && (start || module) && !(start && module) && ret);
1021
1022 id = nodeid;
1023
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001024 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 +01001025 return ((id - nodeid) - r) + 1;
1026 }
1027 id += r;
1028
1029 if ((is_relative && !start) || (!is_relative && !module)) {
1030 return -1;
1031 }
1032
1033 /* descendant-schema-nodeid */
1034 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001035 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001036
1037 /* absolute-schema-nodeid */
1038 } else {
1039 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001040 if (!start_mod) {
1041 return -1;
1042 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001043 start = start_mod->data;
1044 }
1045
1046 while (1) {
1047 sibling = NULL;
1048 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1049 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1050 /* name match */
1051 if ((sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len])
1052 || (!strncmp(name, "input", 5) && (nam_len == 5) && (sibling->nodetype == LYS_INPUT))
1053 || (!strncmp(name, "output", 6) && (nam_len == 6) && (sibling->nodetype == LYS_OUTPUT))) {
1054
1055 /* module check */
1056 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1057 if (!prefix_mod) {
1058 return -1;
1059 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001060 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001061 continue;
1062 }
1063
1064 /* the result node? */
1065 if (!id[0]) {
1066 *ret = sibling;
1067 return EXIT_SUCCESS;
1068 }
1069
1070 /* check for shorthand cases - then 'start' does not change */
1071 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1072 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001073 /* move down the tree, if possible */
1074 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1075 return -1;
1076 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001077 start = sibling->child;
1078 }
1079 break;
1080 }
1081 }
1082
1083 /* no match */
1084 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001085 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001086 return EXIT_SUCCESS;
1087 }
1088
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001089 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 +01001090 return ((id - nodeid) - r) + 1;
1091 }
1092 id += r;
1093 }
1094
1095 /* cannot get here */
1096 LOGINT;
1097 return -1;
1098}
1099
1100/* unique, refine, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1101int
1102resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
1103 const struct lys_node **ret)
1104{
1105 const char *name, *mod_name, *id;
1106 const struct lys_node *sibling;
1107 int r, nam_len, mod_name_len, is_relative = -1;
1108 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko4f0dad02016-02-15 14:08:23 +01001109 const struct lys_module *prefix_mod, *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001110
1111 assert(nodeid && start && ret);
1112 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1113
1114 id = nodeid;
1115 module = start->module;
1116
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001117 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 +01001118 return ((id - nodeid) - r) + 1;
1119 }
1120 id += r;
1121
1122 if (!is_relative) {
1123 return -1;
1124 }
1125
1126 while (1) {
1127 sibling = NULL;
1128 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1129 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1130 /* name match */
1131 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1132
1133 /* module check */
1134 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1135 if (!prefix_mod) {
1136 return -1;
1137 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001138 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001139 continue;
1140 }
1141
1142 /* the result node? */
1143 if (!id[0]) {
1144 if (!(sibling->nodetype & ret_nodetype)) {
1145 /* wrong node type, too bad */
1146 continue;
1147 }
1148 *ret = sibling;
1149 return EXIT_SUCCESS;
1150 }
1151
1152 /* check for shorthand cases - then 'start' does not change */
1153 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1154 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001155 /* move down the tree, if possible */
1156 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1157 return -1;
1158 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001159 start = sibling->child;
1160 }
1161 break;
1162 }
1163 }
1164
1165 /* no match */
1166 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001167 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001168 return EXIT_SUCCESS;
1169 }
1170
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001171 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 +01001172 return ((id - nodeid) - r) + 1;
1173 }
1174 id += r;
1175 }
1176
1177 /* cannot get here */
1178 LOGINT;
1179 return -1;
1180}
1181
1182/* choice default */
1183int
1184resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1185{
1186 /* cannot actually be a path */
1187 if (strchr(nodeid, '/')) {
1188 return -1;
1189 }
1190
1191 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, ret);
1192}
1193
1194/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1195static int
1196resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1197{
1198 const struct lys_module *module;
1199 const char *mod_prefix, *name;
1200 int i, mod_prefix_len, nam_len;
1201
1202 /* parse the identifier, it must be parsed on one call */
1203 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1204 return -i + 1;
1205 }
1206
1207 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1208 if (!module) {
1209 return -1;
1210 }
1211 if (module != start->module) {
1212 start = module->data;
1213 }
1214
1215 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1216
1217 return EXIT_SUCCESS;
1218}
1219
1220int
1221resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1222 const struct lys_node **ret)
1223{
1224 const char *name, *mod_name, *id;
1225 const struct lys_node *sibling, *start;
1226 int r, nam_len, mod_name_len, is_relative = -1;
Michal Vasko4f0dad02016-02-15 14:08:23 +01001227 const struct lys_module *prefix_mod, *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001228
1229 assert(nodeid && module && ret);
1230 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1231
1232 id = nodeid;
1233 start = module->data;
1234
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001235 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 +01001236 return ((id - nodeid) - r) + 1;
1237 }
1238 id += r;
1239
1240 if (is_relative) {
1241 return -1;
1242 }
1243
1244 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001245 if (!abs_start_mod) {
1246 return -1;
1247 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001248
1249 while (1) {
1250 sibling = NULL;
1251 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1252 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1253 /* name match */
1254 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1255
1256 /* module check */
1257 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1258 if (!prefix_mod) {
1259 return -1;
1260 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001261 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001262 continue;
1263 }
1264
1265 /* the result node? */
1266 if (!id[0]) {
1267 if (!(sibling->nodetype & ret_nodetype)) {
1268 /* wrong node type, too bad */
1269 continue;
1270 }
1271 *ret = sibling;
1272 return EXIT_SUCCESS;
1273 }
1274
1275 /* check for shorthand cases - then 'start' does not change */
1276 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1277 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001278 /* move down the tree, if possible */
1279 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
1280 return -1;
1281 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001282 start = sibling->child;
1283 }
1284 break;
1285 }
1286 }
1287
1288 /* no match */
1289 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001290 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001291 return EXIT_SUCCESS;
1292 }
1293
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001294 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 +01001295 return ((id - nodeid) - r) + 1;
1296 }
1297 id += r;
1298 }
1299
1300 /* cannot get here */
1301 LOGINT;
1302 return -1;
1303}
1304
Michal Vaskoe733d682016-03-14 09:08:27 +01001305static int
Michal Vasko3547c532016-03-14 09:40:50 +01001306resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001307{
1308 const char *name;
1309 int nam_len, has_predicate, i;
1310
Michal Vasko3547c532016-03-14 09:40:50 +01001311 if ((i = parse_schema_list_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001312 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001313 return -1;
1314 }
1315
1316 predicate += i;
1317 *parsed += i;
1318
1319 for (i = 0; i < list->keys_size; ++i) {
1320 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1321 break;
1322 }
1323 }
1324
1325 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001326 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001327 return -1;
1328 }
1329
1330 /* more predicates? */
1331 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001332 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001333 }
1334
1335 return 0;
1336}
1337
1338/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
1339const struct lys_node *
Michal Vasko3547c532016-03-14 09:40:50 +01001340resolve_json_schema_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001341{
Radek Krejcib3ecac22016-03-24 10:35:43 +01001342 char *str, module_name[LY_MODULE_NAME_MAX_LEN + 1];
Michal Vasko3edeaf72016-02-11 13:17:43 +01001343 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001344 const struct lys_node *sibling;
Michal Vaskoe733d682016-03-14 09:08:27 +01001345 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001346 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001347 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001348
Michal Vasko3547c532016-03-14 09:40:50 +01001349 assert(nodeid && (ctx || start));
1350 if (!ctx) {
1351 ctx = start->module->ctx;
1352 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001353
1354 id = nodeid;
1355
Michal Vaskoe733d682016-03-14 09:08:27 +01001356 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 +01001357 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001358 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001359 }
1360 id += r;
1361
1362 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001363 assert(start);
1364 start = start->child;
1365 if (!start) {
1366 /* no descendants, fail for sure */
Michal Vasko43c300e2016-03-22 12:54:27 +01001367 LOGVAL(LYE_PATH_INNODE, LY_VLOG_NONE, NULL, name);
Michal Vasko3547c532016-03-14 09:40:50 +01001368 return NULL;
1369 }
1370 module = start->module;
1371 } else {
1372 if (!mod_name) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001373 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_NONE, NULL, name);
Michal Vasko3547c532016-03-14 09:40:50 +01001374 return NULL;
1375 }
1376
1377 str = strndup(mod_name, mod_name_len);
1378 module = ly_ctx_get_module(ctx, str, NULL);
1379 free(str);
1380 if (!module) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001381 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vasko3547c532016-03-14 09:40:50 +01001382 return NULL;
1383 }
1384 start = module->data;
1385
1386 /* now it's as if there was no module name */
1387 mod_name = NULL;
1388 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001389 }
1390
Michal Vaskoe733d682016-03-14 09:08:27 +01001391 prev_mod = module;
1392
Michal Vasko3edeaf72016-02-11 13:17:43 +01001393 while (1) {
1394 sibling = NULL;
1395 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1396 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1397 /* name match */
1398 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
1399
1400 /* module check */
1401 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01001402 if (mod_name_len > LY_MODULE_NAME_MAX_LEN) {
1403 LOGINT;
1404 return NULL;
1405 }
1406 strncpy(module_name, mod_name, mod_name_len);
1407 module_name[mod_name_len] = '\0';
1408 /* will also find an augment module */
1409 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001410 if (!prefix_mod) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001411 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001412 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001413 }
1414 } else {
1415 prefix_mod = prev_mod;
1416 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001417 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001418 continue;
1419 }
1420
Michal Vaskoe733d682016-03-14 09:08:27 +01001421 /* do we have some predicates on it? */
1422 if (has_predicate) {
1423 r = 0;
1424 if (sibling->nodetype != LYS_LIST) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001425 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001426 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001427 } else if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001428 return NULL;
1429 }
1430 id += r;
1431 }
1432
Michal Vasko3edeaf72016-02-11 13:17:43 +01001433 /* the result node? */
1434 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01001435 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001436 }
1437
1438 /* check for shorthand cases - then 'start' does not change */
1439 if (!sibling->parent || (sibling->parent->nodetype != LYS_CHOICE)
1440 || (sibling->nodetype == LYS_CASE)) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01001441 /* move down the tree, if possible */
1442 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001443 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01001444 return NULL;
1445 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001446 start = sibling->child;
1447 }
1448
1449 /* update prev mod */
1450 prev_mod = start->module;
1451 break;
1452 }
1453 }
1454
1455 /* no match */
1456 if (!sibling) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001457 LOGVAL(LYE_PATH_INNODE, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001458 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001459 }
1460
Michal Vaskoe733d682016-03-14 09:08:27 +01001461 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 +01001462 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001463 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001464 }
1465 id += r;
1466 }
1467
1468 /* cannot get here */
1469 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01001470 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001471}
1472
Michal Vasko22448d32016-03-16 13:17:29 +01001473static int
1474resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
1475{
1476 const char *name, *value;
1477 int nam_len, val_len, has_predicate = 1, r;
1478 uint16_t i;
1479 struct ly_set *keys;
1480
Radek Krejci61a86c62016-03-24 11:06:44 +01001481 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01001482 assert(node->schema->nodetype == LYS_LIST);
1483
1484 keys = lyd_get_list_keys(node);
1485
1486 for (i = 0; i < keys->number; ++i) {
1487 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001488 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001489 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001490 }
1491
1492 if ((r = parse_schema_list_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001493 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Radek Krejciba5cec62016-03-24 10:40:29 +01001494 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001495 }
1496
1497 predicate += r;
1498 *parsed += r;
1499
Radek Krejci8f08df12016-03-21 11:11:30 +01001500 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 +01001501 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Radek Krejciba5cec62016-03-24 10:40:29 +01001502 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01001503 }
1504
1505 /* value does not match */
Radek Krejci8f08df12016-03-21 11:11:30 +01001506 if (strncmp(((struct lyd_node_leaf_list *)keys->set.d[i])->value_str, value, val_len)
1507 || ((struct lyd_node_leaf_list *)keys->set.d[i])->value_str[val_len]) {
Radek Krejciba5cec62016-03-24 10:40:29 +01001508 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001509 return 1;
1510 }
1511 }
1512
Radek Krejciba5cec62016-03-24 10:40:29 +01001513 ly_set_free(keys);
Michal Vasko22448d32016-03-16 13:17:29 +01001514 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001515 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01001516 return -1;
1517 }
1518
1519 return 0;
Radek Krejciba5cec62016-03-24 10:40:29 +01001520
1521error:
1522 ly_set_free(keys);
1523 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001524}
1525
1526struct lyd_node *
1527resolve_partial_json_data_nodeid(const char *nodeid, struct lyd_node *start, int *parsed)
1528{
Radek Krejcib3ecac22016-03-24 10:35:43 +01001529 char module_name[LY_MODULE_NAME_MAX_LEN + 1];
Michal Vasko22448d32016-03-16 13:17:29 +01001530 const char *id, *mod_name, *name;
1531 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001532 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko22448d32016-03-16 13:17:29 +01001533 const struct lys_module *prefix_mod, *prev_mod;
1534 struct ly_ctx *ctx;
1535
1536 assert(nodeid && start && parsed);
1537
1538 ctx = start->schema->module->ctx;
1539 id = nodeid;
1540
1541 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 +01001542 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001543 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001544 return NULL;
1545 }
1546 id += r;
1547 /* add it to parsed only after the data node was actually found */
1548 last_parsed = r;
1549
1550 if (is_relative) {
1551 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01001552 start = start->child;
1553 } else {
1554 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01001555 prev_mod = start->schema->module;
1556 }
1557
1558 while (1) {
1559 LY_TREE_FOR(start, sibling) {
1560 /* name match */
1561 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
1562
1563 /* module check */
1564 if (mod_name) {
1565 if (mod_name_len > LY_MODULE_NAME_MAX_LEN) {
1566 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001567 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001568 return NULL;
1569 }
1570 strncpy(module_name, mod_name, mod_name_len);
1571 module_name[mod_name_len] = '\0';
1572 /* will also find an augment module */
1573 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
1574 if (!prefix_mod) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001575 LOGVAL(LYE_PATH_INMOD, LY_VLOG_NONE, NULL, mod_name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001576 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001577 return NULL;
1578 }
1579 } else {
1580 prefix_mod = prev_mod;
1581 }
1582 if (prefix_mod != lys_node_module(sibling->schema)) {
1583 continue;
1584 }
1585
1586 /* leaf-list never matches, it does not make sense */
1587 if (sibling->schema->nodetype == LYS_LEAFLIST) {
1588 sibling = NULL;
1589 break;
1590 }
1591
1592 /* is it a list? we need predicates'n'stuff then */
1593 if (sibling->schema->nodetype == LYS_LIST) {
1594 r = 0;
1595 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001596 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001597 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001598 return NULL;
1599 }
1600 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
1601 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01001602 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001603 return NULL;
1604 } else if (ret == 1) {
1605 /* this list instance does not match */
1606 continue;
1607 }
1608 id += r;
1609 last_parsed += r;
1610 }
1611
1612 *parsed += last_parsed;
1613
1614 /* the result node? */
1615 if (!id[0]) {
1616 return sibling;
1617 }
1618
1619 /* move down the tree, if possible */
1620 if (start->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001621 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001622 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001623 return NULL;
1624 }
1625 last_match = start;
1626 start = sibling->child;
1627 if (start) {
1628 prev_mod = start->schema->module;
1629 }
1630 break;
1631 }
1632 }
1633
1634 /* no match, return last match */
1635 if (!sibling) {
1636 return last_match;
1637 }
1638
1639 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001640 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01001641 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001642 return NULL;
1643 }
1644 id += r;
1645 last_parsed = r;
1646 }
1647
1648 /* cannot get here */
1649 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01001650 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01001651 return NULL;
1652}
1653
Michal Vasko3edeaf72016-02-11 13:17:43 +01001654/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02001655 * @brief Resolves length or range intervals. Does not log.
1656 * Syntax is assumed to be correct, *local_intv MUST be NULL.
1657 *
1658 * @param[in] str_restr The restriction as a string.
1659 * @param[in] type The type of the restriction.
1660 * @param[in] superior_restr Flag whether to check superior
1661 * types.
1662 * @param[out] local_intv The final interval structure.
1663 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001664 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02001665 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001666int
Michal Vasko23b61ec2015-08-19 11:19:50 +02001667resolve_len_ran_interval(const char *str_restr, struct lys_type *type, int superior_restr,
1668 struct len_ran_intv** local_intv)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001669{
1670 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001671 int kind, rc = EXIT_SUCCESS;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001672 int64_t local_smin, local_smax;
1673 uint64_t local_umin, local_umax;
1674 long double local_fmin, local_fmax;
1675 const char *seg_ptr, *ptr;
Michal Vaskoe01eca52015-08-13 14:42:02 +02001676 struct len_ran_intv *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001677
1678 switch (type->base) {
1679 case LY_TYPE_BINARY:
1680 kind = 0;
1681 local_umin = 0;
1682 local_umax = 18446744073709551615UL;
1683
1684 if (!str_restr && type->info.binary.length) {
1685 str_restr = type->info.binary.length->expr;
1686 }
1687 break;
1688 case LY_TYPE_DEC64:
1689 kind = 2;
1690 local_fmin = -9223372036854775808.0;
1691 local_fmin /= 1 << type->info.dec64.dig;
1692 local_fmax = 9223372036854775807.0;
1693 local_fmax /= 1 << type->info.dec64.dig;
1694
1695 if (!str_restr && type->info.dec64.range) {
1696 str_restr = type->info.dec64.range->expr;
1697 }
1698 break;
1699 case LY_TYPE_INT8:
1700 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001701 local_smin = __INT64_C(-128);
1702 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001703
1704 if (!str_restr && type->info.num.range) {
1705 str_restr = type->info.num.range->expr;
1706 }
1707 break;
1708 case LY_TYPE_INT16:
1709 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001710 local_smin = __INT64_C(-32768);
1711 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001712
1713 if (!str_restr && type->info.num.range) {
1714 str_restr = type->info.num.range->expr;
1715 }
1716 break;
1717 case LY_TYPE_INT32:
1718 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001719 local_smin = __INT64_C(-2147483648);
1720 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001721
1722 if (!str_restr && type->info.num.range) {
1723 str_restr = type->info.num.range->expr;
1724 }
1725 break;
1726 case LY_TYPE_INT64:
1727 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01001728 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
1729 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001730
1731 if (!str_restr && type->info.num.range) {
1732 str_restr = type->info.num.range->expr;
1733 }
1734 break;
1735 case LY_TYPE_UINT8:
1736 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001737 local_umin = __UINT64_C(0);
1738 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001739
1740 if (!str_restr && type->info.num.range) {
1741 str_restr = type->info.num.range->expr;
1742 }
1743 break;
1744 case LY_TYPE_UINT16:
1745 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001746 local_umin = __UINT64_C(0);
1747 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001748
1749 if (!str_restr && type->info.num.range) {
1750 str_restr = type->info.num.range->expr;
1751 }
1752 break;
1753 case LY_TYPE_UINT32:
1754 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001755 local_umin = __UINT64_C(0);
1756 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001757
1758 if (!str_restr && type->info.num.range) {
1759 str_restr = type->info.num.range->expr;
1760 }
1761 break;
1762 case LY_TYPE_UINT64:
1763 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001764 local_umin = __UINT64_C(0);
1765 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001766
1767 if (!str_restr && type->info.num.range) {
1768 str_restr = type->info.num.range->expr;
1769 }
1770 break;
1771 case LY_TYPE_STRING:
1772 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01001773 local_umin = __UINT64_C(0);
1774 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001775
1776 if (!str_restr && type->info.str.length) {
1777 str_restr = type->info.str.length->expr;
1778 }
1779 break;
1780 default:
1781 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001782 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001783 }
1784
1785 /* process superior types */
1786 if (type->der && superior_restr) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001787 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1788 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001789 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001790 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001791 assert(!intv || (intv->kind == kind));
1792 }
1793
1794 if (!str_restr) {
1795 /* we are validating data and not have any restriction, but a superior type might have */
1796 if (type->der && !superior_restr && !intv) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001797 if (resolve_len_ran_interval(NULL, &type->der->type, superior_restr, &intv)) {
1798 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001799 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001800 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001801 assert(!intv || (intv->kind == kind));
1802 }
1803 *local_intv = intv;
1804 return EXIT_SUCCESS;
1805 }
1806
1807 /* adjust local min and max */
1808 if (intv) {
1809 tmp_intv = intv;
1810
1811 if (kind == 0) {
1812 local_umin = tmp_intv->value.uval.min;
1813 } else if (kind == 1) {
1814 local_smin = tmp_intv->value.sval.min;
1815 } else if (kind == 2) {
1816 local_fmin = tmp_intv->value.fval.min;
1817 }
1818
1819 while (tmp_intv->next) {
1820 tmp_intv = tmp_intv->next;
1821 }
1822
1823 if (kind == 0) {
1824 local_umax = tmp_intv->value.uval.max;
1825 } else if (kind == 1) {
1826 local_smax = tmp_intv->value.sval.max;
1827 } else if (kind == 2) {
1828 local_fmax = tmp_intv->value.fval.max;
1829 }
1830 }
1831
1832 /* finally parse our restriction */
1833 seg_ptr = str_restr;
1834 while (1) {
Michal Vaskoe01eca52015-08-13 14:42:02 +02001835 if (!*local_intv && !tmp_local_intv) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001836 *local_intv = malloc(sizeof **local_intv);
1837 tmp_local_intv = *local_intv;
1838 } else {
1839 tmp_local_intv->next = malloc(sizeof **local_intv);
1840 tmp_local_intv = tmp_local_intv->next;
1841 }
Michal Vasko253035f2015-12-17 16:58:13 +01001842 if (!tmp_local_intv) {
1843 LOGMEM;
1844 return -1;
1845 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001846
1847 tmp_local_intv->kind = kind;
1848 tmp_local_intv->next = NULL;
1849
1850 /* min */
1851 ptr = seg_ptr;
1852 while (isspace(ptr[0])) {
1853 ++ptr;
1854 }
1855 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1856 if (kind == 0) {
1857 tmp_local_intv->value.uval.min = atoll(ptr);
1858 } else if (kind == 1) {
1859 tmp_local_intv->value.sval.min = atoll(ptr);
1860 } else if (kind == 2) {
1861 tmp_local_intv->value.fval.min = atoll(ptr);
1862 }
1863
1864 if ((ptr[0] == '+') || (ptr[0] == '-')) {
1865 ++ptr;
1866 }
1867 while (isdigit(ptr[0])) {
1868 ++ptr;
1869 }
1870 } else if (!strncmp(ptr, "min", 3)) {
1871 if (kind == 0) {
1872 tmp_local_intv->value.uval.min = local_umin;
1873 } else if (kind == 1) {
1874 tmp_local_intv->value.sval.min = local_smin;
1875 } else if (kind == 2) {
1876 tmp_local_intv->value.fval.min = local_fmin;
1877 }
1878
1879 ptr += 3;
1880 } else if (!strncmp(ptr, "max", 3)) {
1881 if (kind == 0) {
1882 tmp_local_intv->value.uval.min = local_umax;
1883 } else if (kind == 1) {
1884 tmp_local_intv->value.sval.min = local_smax;
1885 } else if (kind == 2) {
1886 tmp_local_intv->value.fval.min = local_fmax;
1887 }
1888
1889 ptr += 3;
1890 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001891 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001892 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001893 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001894 }
1895
1896 while (isspace(ptr[0])) {
1897 ptr++;
1898 }
1899
1900 /* no interval or interval */
1901 if ((ptr[0] == '|') || !ptr[0]) {
1902 if (kind == 0) {
1903 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
1904 } else if (kind == 1) {
1905 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
1906 } else if (kind == 2) {
1907 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
1908 }
1909 } else if (!strncmp(ptr, "..", 2)) {
1910 /* skip ".." */
1911 ptr += 2;
1912 while (isspace(ptr[0])) {
1913 ++ptr;
1914 }
1915
1916 /* max */
1917 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
1918 if (kind == 0) {
1919 tmp_local_intv->value.uval.max = atoll(ptr);
1920 } else if (kind == 1) {
1921 tmp_local_intv->value.sval.max = atoll(ptr);
1922 } else if (kind == 2) {
1923 tmp_local_intv->value.fval.max = atoll(ptr);
1924 }
1925 } else if (!strncmp(ptr, "max", 3)) {
1926 if (kind == 0) {
1927 tmp_local_intv->value.uval.max = local_umax;
1928 } else if (kind == 1) {
1929 tmp_local_intv->value.sval.max = local_smax;
1930 } else if (kind == 2) {
1931 tmp_local_intv->value.fval.max = local_fmax;
1932 }
1933 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001934 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001935 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001936 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001937 }
1938 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02001939 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001940 rc = -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02001941 goto cleanup;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001942 }
1943
1944 /* next segment (next OR) */
1945 seg_ptr = strchr(seg_ptr, '|');
1946 if (!seg_ptr) {
1947 break;
1948 }
1949 seg_ptr++;
1950 }
1951
1952 /* check local restrictions against superior ones */
1953 if (intv) {
1954 tmp_intv = intv;
1955 tmp_local_intv = *local_intv;
1956
1957 while (tmp_local_intv && tmp_intv) {
1958 /* reuse local variables */
1959 if (kind == 0) {
1960 local_umin = tmp_local_intv->value.uval.min;
1961 local_umax = tmp_local_intv->value.uval.max;
1962
1963 /* it must be in this interval */
1964 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
1965 /* this interval is covered, next one */
1966 if (local_umax <= tmp_intv->value.uval.max) {
1967 tmp_local_intv = tmp_local_intv->next;
1968 continue;
1969 /* ascending order of restrictions -> fail */
1970 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001971 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001972 goto cleanup;
1973 }
1974 }
1975 } else if (kind == 1) {
1976 local_smin = tmp_local_intv->value.sval.min;
1977 local_smax = tmp_local_intv->value.sval.max;
1978
1979 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
1980 if (local_smax <= tmp_intv->value.sval.max) {
1981 tmp_local_intv = tmp_local_intv->next;
1982 continue;
1983 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001984 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001985 goto cleanup;
1986 }
1987 }
1988 } else if (kind == 2) {
1989 local_fmin = tmp_local_intv->value.fval.min;
1990 local_fmax = tmp_local_intv->value.fval.max;
1991
1992 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
1993 if (local_fmax <= tmp_intv->value.fval.max) {
1994 tmp_local_intv = tmp_local_intv->next;
1995 continue;
1996 } else {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02001997 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02001998 goto cleanup;
1999 }
2000 }
2001 }
2002
2003 tmp_intv = tmp_intv->next;
2004 }
2005
2006 /* some interval left uncovered -> fail */
2007 if (tmp_local_intv) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002008 rc = -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002009 }
2010
2011 }
2012
2013cleanup:
2014 while (intv) {
2015 tmp_intv = intv->next;
2016 free(intv);
2017 intv = tmp_intv;
2018 }
2019
2020 /* fail */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002021 if (rc) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002022 while (*local_intv) {
2023 tmp_local_intv = (*local_intv)->next;
2024 free(*local_intv);
2025 *local_intv = tmp_local_intv;
2026 }
2027 }
2028
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002029 return rc;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002030}
2031
Michal Vasko730dfdf2015-08-11 14:48:05 +02002032/**
Michal Vasko88c29542015-11-27 14:57:53 +01002033 * @brief Resolve a typedef, return only resolved typedefs if derived. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002034 *
2035 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002036 * @param[in] mod_name Typedef name module name.
2037 * @param[in] module Main module.
2038 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002039 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002040 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002041 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002042 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002043int
Michal Vasko1e62a092015-12-01 12:27:20 +01002044resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2045 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002046{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002047 int i, j;
Radek Krejci1574a8d2015-08-03 14:16:52 +02002048 struct lys_tpdf *tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002049 int tpdf_size;
2050
Michal Vasko1dca6882015-10-22 14:29:42 +02002051 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002052 /* no prefix, try built-in types */
2053 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2054 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002055 if (ret) {
2056 *ret = ly_types[i].def;
2057 }
2058 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002059 }
2060 }
2061 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002062 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002063 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002064 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002065 }
2066 }
2067
Michal Vasko1dca6882015-10-22 14:29:42 +02002068 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002069 /* search in local typedefs */
2070 while (parent) {
2071 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002072 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002073 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2074 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002075 break;
2076
Radek Krejci76512572015-08-04 09:47:08 +02002077 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002078 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2079 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002080 break;
2081
Radek Krejci76512572015-08-04 09:47:08 +02002082 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002083 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2084 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002085 break;
2086
Radek Krejci76512572015-08-04 09:47:08 +02002087 case LYS_RPC:
Radek Krejcib8048692015-08-05 13:36:34 +02002088 tpdf_size = ((struct lys_node_rpc *)parent)->tpdf_size;
2089 tpdf = ((struct lys_node_rpc *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002090 break;
2091
Radek Krejci76512572015-08-04 09:47:08 +02002092 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002093 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2094 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002095 break;
2096
Radek Krejci76512572015-08-04 09:47:08 +02002097 case LYS_INPUT:
2098 case LYS_OUTPUT:
Radek Krejci4608ada2015-08-05 16:04:37 +02002099 tpdf_size = ((struct lys_node_rpc_inout *)parent)->tpdf_size;
2100 tpdf = ((struct lys_node_rpc_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002101 break;
2102
2103 default:
2104 parent = parent->parent;
2105 continue;
2106 }
2107
2108 for (i = 0; i < tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002109 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002110 if (ret) {
2111 *ret = &tpdf[i];
2112 }
2113 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002114 }
2115 }
2116
2117 parent = parent->parent;
2118 }
Radek Krejcic071c542016-01-27 14:57:51 +01002119 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002120 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002121 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002122 if (!module) {
2123 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002124 }
2125 }
2126
2127 /* search in top level typedefs */
2128 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002129 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002130 if (ret) {
2131 *ret = &module->tpdf[i];
2132 }
2133 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002134 }
2135 }
2136
2137 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002138 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002139 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko88c29542015-11-27 14:57:53 +01002140 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 +02002141 if (ret) {
2142 *ret = &module->inc[i].submodule->tpdf[j];
2143 }
2144 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002145 }
2146 }
2147 }
2148
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002149 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002150}
2151
Michal Vasko1dca6882015-10-22 14:29:42 +02002152/**
2153 * @brief Check the default \p value of the \p type. Logs directly.
2154 *
2155 * @param[in] type Type definition to use.
2156 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002157 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002158 *
2159 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2160 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002161static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002162check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002163{
Michal Vasko1dca6882015-10-22 14:29:42 +02002164 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002165 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002166
2167 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002168 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002169 node.value_str = value;
2170 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002171 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002172 if (!node.schema) {
2173 LOGMEM;
2174 return -1;
2175 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002176 node.schema->name = strdup("default");
Michal Vasko253035f2015-12-17 16:58:13 +01002177 if (!node.schema->name) {
2178 LOGMEM;
2179 return -1;
2180 }
Michal Vasko56826402016-03-02 11:11:37 +01002181 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002182 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002183
Radek Krejci37b756f2016-01-18 10:15:03 +01002184 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002185 if (!type->info.lref.target) {
2186 ret = EXIT_FAILURE;
2187 goto finish;
2188 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002189 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002190
2191 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2192 /* it was converted to JSON format before, nothing else sensible we can do */
2193
2194 } else {
Radek Krejci0b7704f2016-03-18 12:16:14 +01002195 ret = lyp_parse_value(&node, NULL, 1);
Michal Vasko1dca6882015-10-22 14:29:42 +02002196 }
2197
2198finish:
2199 if (node.value_type == LY_TYPE_BITS) {
2200 free(node.value.bit);
2201 }
2202 free((char *)node.schema->name);
2203 free(node.schema);
2204
2205 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002206}
2207
Michal Vasko730dfdf2015-08-11 14:48:05 +02002208/**
2209 * @brief Check a key for mandatory attributes. Logs directly.
2210 *
2211 * @param[in] key The key to check.
2212 * @param[in] flags What flags to check.
2213 * @param[in] list The list of all the keys.
2214 * @param[in] index Index of the key in the key list.
2215 * @param[in] name The name of the keys.
2216 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002217 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002218 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002219 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002220static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002221check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002222{
Radek Krejciadb57612016-02-16 13:34:34 +01002223 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002224 char *dup = NULL;
2225 int j;
2226
2227 /* existence */
2228 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002229 if (name[len] != '\0') {
2230 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002231 if (!dup) {
2232 LOGMEM;
2233 return -1;
2234 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002235 dup[len] = '\0';
2236 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002237 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002238 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002239 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002240 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002241 }
2242
2243 /* uniqueness */
2244 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002245 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002246 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002247 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002248 }
2249 }
2250
2251 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02002252 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002253 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002254 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002255 }
2256
2257 /* type of the leaf is not built-in empty */
2258 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002259 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002260 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002261 }
2262
2263 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01002264 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002265 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002266 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002267 }
2268
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002269 /* key is not placed from augment */
2270 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002271 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
2272 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01002273 return -1;
2274 }
2275
Michal Vaskocca47842016-03-17 10:31:07 +01002276 /* key is not when-conditional */
2277 if (key->when) {
Radek Krejci02a04992016-03-17 16:06:37 +01002278 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, "when", "leaf");
2279 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"when\" condition.");
Radek Krejci581ce772015-11-10 17:22:40 +01002280 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002281 }
2282
Michal Vasko0b85aa82016-03-07 14:37:43 +01002283 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02002284}
Michal Vasko730dfdf2015-08-11 14:48:05 +02002285
2286/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002287 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002288 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002289 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01002290 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002291 *
2292 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
2293 */
2294int
Radek Krejci48464ed2016-03-17 15:44:09 +01002295resolve_unique(struct lys_node *parent, const char *uniq_str_path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002296{
Radek Krejci581ce772015-11-10 17:22:40 +01002297 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01002298 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002299
Michal Vasko0b85aa82016-03-07 14:37:43 +01002300 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01002301 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01002302 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002303 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002304 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002305 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejci581ce772015-11-10 17:22:40 +01002306 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01002307 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01002308 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01002309 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2310 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01002311 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002312 }
Radek Krejci581ce772015-11-10 17:22:40 +01002313 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002314 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01002315 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002316 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
2317 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejci581ce772015-11-10 17:22:40 +01002318 rc = -1;
2319 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002320 }
2321
Radek Krejcicf509982015-12-15 09:22:44 +01002322 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01002323 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002324 return -1;
2325 }
2326
Radek Krejcica7efb72016-01-18 13:06:01 +01002327 /* set leaf's unique flag */
2328 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
2329
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002330 return EXIT_SUCCESS;
2331
2332error:
2333
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002334 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002335}
2336
Michal Vasko730dfdf2015-08-11 14:48:05 +02002337/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002338 * @brief Resolve (find) a feature definition. Logs directly.
2339 *
2340 * @param[in] name Feature name.
2341 * @param[in] module Module to search in.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002342 * @param[out] ret Pointer to the resolved feature. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002343 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002344 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002345 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002346static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002347resolve_feature(const char *id, const struct lys_module *module, struct lys_feature **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002348{
Michal Vasko2d851a92015-10-20 16:16:36 +02002349 const char *mod_name, *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02002350 int mod_name_len, nam_len, i, j;
Radek Krejcicf509982015-12-15 09:22:44 +01002351 struct lys_node *node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002352
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002353 assert(id);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002354 assert(module);
2355
2356 /* check prefix */
Michal Vasko2d851a92015-10-20 16:16:36 +02002357 if ((i = parse_node_identifier(id, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002358 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002359 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002360 }
2361
Radek Krejcic071c542016-01-27 14:57:51 +01002362 module = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
2363 if (!module) {
2364 /* identity refers unknown data model */
Radek Krejci48464ed2016-03-17 15:44:09 +01002365 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Radek Krejcic071c542016-01-27 14:57:51 +01002366 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002367 }
2368
Radek Krejcic071c542016-01-27 14:57:51 +01002369 /* search in the identified module ... */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002370 for (j = 0; j < module->features_size; j++) {
2371 if (!strcmp(name, module->features[j].name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002372 if (ret) {
Radek Krejcicf509982015-12-15 09:22:44 +01002373 /* check status */
2374 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002375 if (lyp_check_status(node->flags, node->module, node->name, module->features[j].flags,
Radek Krejci48464ed2016-03-17 15:44:09 +01002376 module->features[j].module, module->features[j].name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01002377 return -1;
2378 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002379 *ret = &module->features[j];
2380 }
2381 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002382 }
2383 }
Radek Krejcic071c542016-01-27 14:57:51 +01002384 /* ... and all its submodules */
Michal Vasko27ab8222016-02-12 09:33:52 +01002385 for (i = 0; i < module->inc_size; i++) {
2386 if (!module->inc[i].submodule) {
2387 /* not yet resolved */
2388 continue;
2389 }
Radek Krejcic071c542016-01-27 14:57:51 +01002390 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
2391 if (!strcmp(name, module->inc[i].submodule->features[j].name)) {
2392 if (ret) {
2393 /* check status */
2394 node = (struct lys_node *)*ret;
Radek Krejcic6556022016-01-27 15:16:45 +01002395 if (lyp_check_status(node->flags, node->module, node->name,
Radek Krejcic071c542016-01-27 14:57:51 +01002396 module->inc[i].submodule->features[j].flags,
2397 module->inc[i].submodule->features[j].module,
Radek Krejci48464ed2016-03-17 15:44:09 +01002398 module->inc[i].submodule->features[j].name, node)) {
Radek Krejcic071c542016-01-27 14:57:51 +01002399 return -1;
2400 }
2401 *ret = &(module->inc[i].submodule->features[j]);
2402 }
2403 return EXIT_SUCCESS;
2404 }
2405 }
2406 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002407
2408 /* not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01002409 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", id);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002410 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002411}
2412
Radek Krejci0c0086a2016-03-24 15:20:28 +01002413void
Michal Vasko23b61ec2015-08-19 11:19:50 +02002414unres_data_del(struct unres_data *unres, uint32_t i)
2415{
2416 /* there are items after the one deleted */
2417 if (i+1 < unres->count) {
2418 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02002419 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002420
2421 /* deleting the last item */
2422 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02002423 free(unres->node);
2424 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002425 }
2426
2427 /* if there are no items after and it is not the last one, just move the counter */
2428 --unres->count;
2429}
2430
Michal Vasko0491ab32015-08-19 14:28:29 +02002431/**
2432 * @brief Resolve (find) a data node from a specific module. Does not log.
2433 *
2434 * @param[in] mod Module to search in.
2435 * @param[in] name Name of the data node.
2436 * @param[in] nam_len Length of the name.
2437 * @param[in] start Data node to start the search from.
2438 * @param[in,out] parents Resolved nodes. If there are some parents,
2439 * they are replaced (!!) with the resolvents.
2440 *
2441 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
2442 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002443static int
Michal Vasko1e62a092015-12-01 12:27:20 +01002444resolve_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 +02002445{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002446 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02002447 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002448 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002449
Michal Vasko23b61ec2015-08-19 11:19:50 +02002450 if (!parents->count) {
2451 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002452 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002453 if (!parents->node) {
2454 LOGMEM;
2455 return EXIT_FAILURE;
2456 }
Michal Vaskocf024702015-10-08 15:01:42 +02002457 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002458 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002459 for (i = 0; i < parents->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002460 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002461 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002462 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002463 continue;
2464 }
2465 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002466 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002467 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
2468 && node->schema->name[nam_len] == '\0') {
2469 /* matching target */
2470 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02002471 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02002472 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002473 flag = 1;
2474 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02002475 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002476 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01002477 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
2478 if (!parents->node) {
2479 return EXIT_FAILURE;
2480 }
Michal Vaskocf024702015-10-08 15:01:42 +02002481 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002482 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002483 }
2484 }
2485 }
Radek Krejcic5090c32015-08-12 09:46:19 +02002486
2487 if (!flag) {
2488 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002489 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02002490 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002491 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02002492 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002493 }
2494
Michal Vasko0491ab32015-08-19 14:28:29 +02002495 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02002496}
2497
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002498/**
2499 * @brief Resolve (find) a data node. Does not log.
2500 *
Radek Krejci581ce772015-11-10 17:22:40 +01002501 * @param[in] mod_name Module name of the data node.
2502 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002503 * @param[in] name Name of the data node.
2504 * @param[in] nam_len Length of the name.
2505 * @param[in] start Data node to start the search from.
2506 * @param[in,out] parents Resolved nodes. If there are some parents,
2507 * they are replaced (!!) with the resolvents.
2508 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002509 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002510 */
Radek Krejcic5090c32015-08-12 09:46:19 +02002511static int
Radek Krejci581ce772015-11-10 17:22:40 +01002512resolve_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 +02002513 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02002514{
Michal Vasko1e62a092015-12-01 12:27:20 +01002515 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02002516 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02002517
Michal Vasko23b61ec2015-08-19 11:19:50 +02002518 assert(start);
2519
Michal Vasko31fc3672015-10-21 12:08:13 +02002520 if (mod_name) {
2521 /* we have mod_name, find appropriate module */
2522 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01002523 if (!str) {
2524 LOGMEM;
2525 return -1;
2526 }
Michal Vasko31fc3672015-10-21 12:08:13 +02002527 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
2528 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02002529 if (!mod) {
2530 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002531 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02002532 }
2533 } else {
2534 /* no prefix, module is the same as of current node */
2535 mod = start->schema->module;
2536 }
2537
2538 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002539}
2540
Michal Vasko730dfdf2015-08-11 14:48:05 +02002541/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002542 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01002543 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002544 *
Michal Vaskobb211122015-08-19 14:03:11 +02002545 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002546 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02002547 * @param[in,out] node_match Nodes satisfying the restriction
2548 * without the predicate. Nodes not
2549 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02002550 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002551 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002552 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002553 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002554static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002555resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01002556 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002557{
Michal Vasko730dfdf2015-08-11 14:48:05 +02002558 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002559 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002560 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02002561 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
2562 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002563 uint32_t j;
2564
2565 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002566 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002567 if (!source_match.node) {
2568 LOGMEM;
2569 return -1;
2570 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002571 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002572 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01002573 if (!dest_match.node) {
2574 LOGMEM;
2575 return -1;
2576 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002577
2578 do {
2579 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
2580 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002581 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002582 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002583 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002584 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002585 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002586 pred += i;
2587
Michal Vasko23b61ec2015-08-19 11:19:50 +02002588 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002589 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02002590 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002591
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002592 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01002593 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02002594 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002595 i = 0;
2596 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002597 }
2598
2599 /* destination */
Michal Vaskocf024702015-10-08 15:01:42 +02002600 dest_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02002601 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002602 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2603 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002604 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002605 rc = -1;
2606 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002607 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02002608 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002609 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02002610 dest_match.node[0] = dest_match.node[0]->parent;
2611 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002612 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02002613 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002614 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002615 }
2616 }
2617 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01002618 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02002619 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02002620 i = 0;
2621 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002622 }
2623
2624 if (pke_len == pke_parsed) {
2625 break;
2626 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002627 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 +02002628 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002629 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002630 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002631 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002632 }
2633 pke_parsed += i;
2634 }
2635
2636 /* check match between source and destination nodes */
Michal Vaskocf024702015-10-08 15:01:42 +02002637 if (((struct lys_node_leaf *)source_match.node[0]->schema)->type.base
2638 != ((struct lys_node_leaf *)dest_match.node[0]->schema)->type.base) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002639 goto remove_leafref;
2640 }
2641
Radek Krejcic1ffa4d2016-02-17 13:11:11 +01002642 if (!ly_strequal(((struct lyd_node_leaf_list *)source_match.node[0])->value_str,
Radek Krejci749190d2016-02-18 16:26:25 +01002643 ((struct lyd_node_leaf_list *)dest_match.node[0])->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002644 goto remove_leafref;
2645 }
2646
2647 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002648 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002649 continue;
2650
2651remove_leafref:
2652 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002653 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002654 }
2655 } while (has_predicate);
2656
Michal Vaskocf024702015-10-08 15:01:42 +02002657 free(source_match.node);
2658 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02002659 if (parsed) {
2660 *parsed = parsed_loc;
2661 }
2662 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002663
2664error:
2665
2666 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002667 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002668 }
2669 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02002670 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002671 }
Michal Vasko0491ab32015-08-19 14:28:29 +02002672 if (parsed) {
2673 *parsed = -parsed_loc+i;
2674 }
2675 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002676}
2677
Michal Vasko730dfdf2015-08-11 14:48:05 +02002678/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002679 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002680 *
Michal Vaskocf024702015-10-08 15:01:42 +02002681 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02002682 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01002683 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002684 *
Michal Vasko0491ab32015-08-19 14:28:29 +02002685 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002686 */
Michal Vasko184521f2015-09-24 13:14:26 +02002687static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002688resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002689{
Radek Krejci71b795b2015-08-10 16:20:39 +02002690 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002691 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02002692 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002693 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002694
Michal Vaskocf024702015-10-08 15:01:42 +02002695 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02002696
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002697 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02002698 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002699
2700 /* searching for nodeset */
2701 do {
2702 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002703 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02002704 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002705 goto error;
2706 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002707 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002708 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002709
Michal Vasko23b61ec2015-08-19 11:19:50 +02002710 if (!ret->count) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02002711 if (parent_times != -1) {
2712 ret->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02002713 ret->node = calloc(1, sizeof *ret->node);
Michal Vasko253035f2015-12-17 16:58:13 +01002714 if (!ret->node) {
2715 LOGMEM;
Radek Krejci50501732016-01-07 13:06:39 +01002716 rc = -1;
Michal Vasko253035f2015-12-17 16:58:13 +01002717 goto error;
2718 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02002719 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002720 for (i = 0; i < parent_times; ++i) {
2721 /* relative path */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002722 if (!ret->count) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002723 /* error, too many .. */
Radek Krejci48464ed2016-03-17 15:44:09 +01002724 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, path, node->schema->name);
Michal Vasko0491ab32015-08-19 14:28:29 +02002725 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002726 goto error;
Michal Vaskocf024702015-10-08 15:01:42 +02002727 } else if (!ret->node[0]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002728 /* first .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002729 data = ret->node[0] = node->parent;
2730 } else if (!ret->node[0]->parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002731 /* we are in root */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002732 ret->count = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02002733 free(ret->node);
2734 ret->node = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002735 } else {
2736 /* multiple .. */
Michal Vaskocf024702015-10-08 15:01:42 +02002737 data = ret->node[0] = ret->node[0]->parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002738 }
2739 }
2740
2741 /* absolute path */
2742 if (parent_times == -1) {
Michal Vaskocf024702015-10-08 15:01:42 +02002743 for (data = node; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02002744 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko8bcdf292015-08-19 14:04:43 +02002745 if (data->prev) {
2746 for (; data->prev->next; data = data->prev);
2747 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002748 }
2749 }
2750
2751 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01002752 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002753 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002754 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02002755 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002756 goto error;
2757 }
2758
2759 if (has_predicate) {
2760 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002761 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02002762 if (ret->node[j]->schema->nodetype == LYS_LIST &&
2763 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002764 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002765 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002766 continue;
2767 }
2768
2769 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02002770 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002771 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002772 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002773 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002774 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002775 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002776 goto error;
2777 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002778 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02002779 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780
Michal Vasko23b61ec2015-08-19 11:19:50 +02002781 if (!ret->count) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002782 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, path-parsed);
Michal Vasko0491ab32015-08-19 14:28:29 +02002783 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002784 goto error;
2785 }
2786 }
2787 } while (path[0] != '\0');
2788
Michal Vaskof02e3742015-08-05 16:27:02 +02002789 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002790
2791error:
2792
Michal Vaskocf024702015-10-08 15:01:42 +02002793 free(ret->node);
2794 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02002795 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002796
Michal Vasko0491ab32015-08-19 14:28:29 +02002797 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002798}
2799
Michal Vasko730dfdf2015-08-11 14:48:05 +02002800/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002801 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002802 *
Michal Vaskobb211122015-08-19 14:03:11 +02002803 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01002804 * @param[in] context_node Predicate context node (where the predicate is placed).
2805 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02002806 *
Michal Vasko184521f2015-09-24 13:14:26 +02002807 * @return 0 on forward reference, otherwise the number
2808 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002809 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002810 */
Michal Vasko1f76a282015-08-04 16:16:53 +02002811static int
Radek Krejciadb57612016-02-16 13:34:34 +01002812resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01002813 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02002814{
Michal Vasko1e62a092015-12-01 12:27:20 +01002815 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02002816 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
2817 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 +02002818 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002819
2820 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02002821 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02002822 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002823 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002824 return -parsed+i;
2825 }
2826 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02002827 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02002828
Michal Vasko58090902015-08-13 14:04:15 +02002829 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01002830 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01002831 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01002832 }
Radek Krejciadb57612016-02-16 13:34:34 +01002833 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002834 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002835 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002836 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002837 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02002838 }
2839 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002840 }
2841
2842 /* destination */
2843 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
2844 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002845 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 +02002846 return -parsed;
2847 }
2848 pke_parsed += i;
2849
Radek Krejciadb57612016-02-16 13:34:34 +01002850 /* parent is actually the parent of this leaf, so skip the first ".." */
2851 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002852 if (!dst_node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002853 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002854 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002855 }
Radek Krejciadb57612016-02-16 13:34:34 +01002856 dst_node = dst_node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002857 }
2858 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01002859 if (!dest_pref) {
2860 dest_pref = dst_node->module->name;
2861 }
2862 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02002863 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002864 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002865 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002866 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02002867 }
2868 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002869 }
2870
2871 if (pke_len == pke_parsed) {
2872 break;
2873 }
2874
2875 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
2876 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002877 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01002878 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02002879 return -parsed;
2880 }
2881 pke_parsed += i;
2882 }
2883
2884 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02002885 if (dst_node->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002886 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path-parsed);
2887 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
2888 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02002889 return -parsed;
2890 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002891 } while (has_predicate);
2892
2893 return parsed;
2894}
2895
Michal Vasko730dfdf2015-08-11 14:48:05 +02002896/**
Michal Vaskof39142b2015-10-21 11:40:05 +02002897 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002898 *
Michal Vaskobb211122015-08-19 14:03:11 +02002899 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002900 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01002901 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
2902 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002903 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002904 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002905 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002906 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002907static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002908resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01002909 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02002910{
Michal Vasko1e62a092015-12-01 12:27:20 +01002911 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01002912 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02002913 const char *id, *prefix, *name;
2914 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02002915 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002916
Michal Vasko184521f2015-09-24 13:14:26 +02002917 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002918 parent_times = 0;
2919 id = path;
2920
2921 do {
2922 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002923 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 +02002924 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002925 }
2926 id += i;
2927
Michal Vasko184521f2015-09-24 13:14:26 +02002928 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002929 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01002930 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01002931 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01002932 /* get start node */
2933 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02002934 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002935 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002936 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02002937 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002938 } else if (parent_times > 0) {
Michal Vasko73ae2562015-08-06 11:58:13 +02002939 /* node is the parent already, skip one ".." */
Radek Krejci2f12f852016-01-08 12:59:57 +01002940 if (parent_tpdf) {
2941 /* the path is not allowed to contain relative path since we are in top level typedef */
Radek Krejci48464ed2016-03-17 15:44:09 +01002942 LOGVAL(LYE_NORESOLV, 0, NULL, path);
Radek Krejci2f12f852016-01-08 12:59:57 +01002943 return -1;
2944 }
2945
Radek Krejciadb57612016-02-16 13:34:34 +01002946 node = parent;
Michal Vasko58090902015-08-13 14:04:15 +02002947 i = 0;
2948 while (1) {
Michal Vasko1f76a282015-08-04 16:16:53 +02002949 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002950 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002951 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02002952 }
Michal Vasko58090902015-08-13 14:04:15 +02002953
2954 /* this node is a wrong node, we actually need the augment target */
2955 if (node->nodetype == LYS_AUGMENT) {
2956 node = ((struct lys_node_augment *)node)->target;
2957 if (!node) {
2958 continue;
2959 }
2960 }
2961
2962 ++i;
2963 if (i == parent_times) {
2964 break;
2965 }
2966 node = node->parent;
Michal Vasko1f76a282015-08-04 16:16:53 +02002967 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002968
Michal Vasko1f76a282015-08-04 16:16:53 +02002969 node = node->child;
Michal Vaskoe01eca52015-08-13 14:42:02 +02002970 } else {
2971 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002972 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02002973 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01002974
Michal Vasko184521f2015-09-24 13:14:26 +02002975 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02002976 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002977 /* move down the tree, if possible */
2978 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYXML)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01002979 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 +01002980 return -1;
2981 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002982 node = node->child;
2983 }
2984
Michal Vasko4f0dad02016-02-15 14:08:23 +01002985 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01002986 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01002987 }
2988
Michal Vasko36cbaa42015-12-14 13:15:48 +01002989 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 +02002990 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01002991 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002992 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko184521f2015-09-24 13:14:26 +02002993 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002994 return rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02002995 }
Michal Vasko1f76a282015-08-04 16:16:53 +02002996
2997 if (has_predicate) {
2998 /* we have predicate, so the current result must be list */
2999 if (node->nodetype != LYS_LIST) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003000 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003001 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003002 }
3003
Radek Krejci48464ed2016-03-17 15:44:09 +01003004 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003005 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003006 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003007 } else if (i < 0) {
3008 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003009 }
3010 id += i;
3011 }
3012 } while (id[0]);
3013
Radek Krejcib1c12512015-08-11 11:22:04 +02003014 /* the target must be leaf or leaf-list */
3015 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003016 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003017 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003018 }
3019
Radek Krejcicf509982015-12-15 09:22:44 +01003020 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003021 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003022 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003023 return -1;
3024 }
3025
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003026 if (ret) {
3027 *ret = node;
3028 }
3029 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003030}
3031
Michal Vasko730dfdf2015-08-11 14:48:05 +02003032/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003033 * @brief Resolve instance-identifier predicate in JSON data format.
3034 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003035 *
Michal Vaskobb211122015-08-19 14:03:11 +02003036 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003037 * @param[in,out] node_match Nodes matching the restriction without
3038 * the predicate. Nodes not satisfying
3039 * the predicate are removed.
3040 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003041 * @return Number of characters successfully parsed,
3042 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003043 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003044static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003045resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003046{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003047 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003048 struct unres_data target_match;
3049 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003050 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003051 const char *model, *name, *value;
3052 char *str;
3053 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3054 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003055
Michal Vasko1f2cc332015-08-19 11:18:32 +02003056 assert(pred && node_match->count);
3057
Michal Vaskocf024702015-10-08 15:01:42 +02003058 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003059 idx = -1;
3060 parsed = 0;
3061
3062 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003063 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003064 return -parsed+i;
3065 }
3066 parsed += i;
3067 pred += i;
3068
Michal Vasko1f2cc332015-08-19 11:18:32 +02003069 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003070 if (isdigit(name[0])) {
3071 idx = atoi(name);
3072 }
3073
Michal Vasko1f2cc332015-08-19 11:18:32 +02003074 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003075 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003076 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003077 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003078 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003079 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003080 if (!target_match.node) {
3081 LOGMEM;
3082 return -1;
3083 }
Michal Vaskocf024702015-10-08 15:01:42 +02003084 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003085 } else {
3086 str = strndup(model, mod_len);
3087 mod = ly_ctx_get_module(ctx, str, NULL);
3088 free(str);
3089
Radek Krejci804836a2016-02-03 10:39:55 +01003090 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003091 goto remove_instid;
3092 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003093 }
3094
3095 /* check that we have the correct type */
3096 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003097 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098 goto remove_instid;
3099 }
3100 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003101 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 goto remove_instid;
3103 }
3104 }
3105
Michal Vasko83a6c462015-10-08 16:43:53 +02003106 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3107 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003108 || (!value && (idx != cur_idx))) {
3109 goto remove_instid;
3110 }
3111
Michal Vaskocf024702015-10-08 15:01:42 +02003112 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113
3114 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003115 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116 continue;
3117
3118remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003119 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003120
3121 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003122 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003123 }
3124 } while (has_predicate);
3125
3126 return parsed;
3127}
3128
Michal Vasko730dfdf2015-08-11 14:48:05 +02003129/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003130 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003131 *
Radek Krejciadb57612016-02-16 13:34:34 +01003132 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003133 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003134 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003135 * @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 +02003136 */
Michal Vasko184521f2015-09-24 13:14:26 +02003137static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003138resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003139{
Radek Krejcic5090c32015-08-12 09:46:19 +02003140 int i = 0, j;
3141 struct lyd_node *result = NULL;
Michal Vasko1e62a092015-12-01 12:27:20 +01003142 const struct lys_module *mod = NULL;
Radek Krejcic5090c32015-08-12 09:46:19 +02003143 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003144 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003145 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003146 int mod_len, name_len, has_predicate;
3147 struct unres_data node_match;
3148 uint32_t k;
3149
3150 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151
Radek Krejcic5090c32015-08-12 09:46:19 +02003152 /* we need root to resolve absolute path */
3153 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003154 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003155 if (data->prev) {
3156 for (; data->prev->next; data = data->prev);
3157 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158
Radek Krejcic5090c32015-08-12 09:46:19 +02003159 /* search for the instance node */
3160 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003161 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003162 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003163 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003164 goto error;
3165 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003166 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003167
Michal Vasko1f2cc332015-08-19 11:18:32 +02003168 str = strndup(model, mod_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003169 if (!str) {
3170 LOGMEM;
3171 goto error;
3172 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003173 mod = ly_ctx_get_module(ctx, str, NULL);
3174 free(str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003175
Radek Krejcic5090c32015-08-12 09:46:19 +02003176 if (!mod) {
3177 /* no instance exists */
3178 return NULL;
3179 }
3180
Michal Vasko1f2cc332015-08-19 11:18:32 +02003181 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003182 /* no instance exists */
3183 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003184 }
3185
3186 if (has_predicate) {
3187 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003188 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003189 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3190 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3191 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003192 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003193 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003194 continue;
3195 }
3196
3197 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003198 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003199 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003200
Michal Vaskof39142b2015-10-21 11:40:05 +02003201 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003202 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003203 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003204 goto error;
3205 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003206 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003207
Michal Vasko1f2cc332015-08-19 11:18:32 +02003208 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003209 /* no instance exists */
3210 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003211 }
3212 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003213 }
3214
Michal Vasko1f2cc332015-08-19 11:18:32 +02003215 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003216 /* no instance exists */
3217 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003218 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003219 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003220 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003221
3222 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003223 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003224
3225 return NULL;
3226 } else {
3227 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003228 result = node_match.node[0];
3229 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003230
3231 return result;
3232 }
3233
3234error:
3235
3236 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003237 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003238
3239 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240}
3241
Michal Vasko730dfdf2015-08-11 14:48:05 +02003242/**
3243 * @brief Passes config flag down to children. Does not log.
3244 *
3245 * @param[in] node Parent node.
3246 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003247static void
Radek Krejci1d82ef62015-08-07 14:44:40 +02003248inherit_config_flag(struct lys_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249{
Radek Krejci1d82ef62015-08-07 14:44:40 +02003250 LY_TREE_FOR(node, node) {
3251 node->flags |= node->parent->flags & LYS_CONFIG_MASK;
3252 inherit_config_flag(node->child);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253 }
3254}
3255
Michal Vasko730dfdf2015-08-11 14:48:05 +02003256/**
Michal Vasko7178e692016-02-12 15:58:05 +01003257 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003258 *
Michal Vaskobb211122015-08-19 14:03:11 +02003259 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003260 * @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 +02003261 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003262 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003263 */
Michal Vasko7178e692016-02-12 15:58:05 +01003264static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003265resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003267 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02003268 struct lys_node *sub;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003269
Michal Vasko1d87a922015-08-21 12:57:16 +02003270 assert(aug);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271
3272 /* resolve target node */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003273 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 +01003274 if (rc == -1) {
3275 return -1;
3276 }
3277 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003278 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003279 return -1;
3280 }
3281 if (!aug->target) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003282 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003283 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284 }
3285
3286 if (!aug->child) {
3287 /* nothing to do */
Michal Vasko1d87a922015-08-21 12:57:16 +02003288 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 return EXIT_SUCCESS;
3290 }
3291
Michal Vaskod58d5962016-03-02 14:29:41 +01003292 /* check for mandatory nodes - if the target node is in another module
3293 * the added nodes cannot be mandatory
3294 */
3295 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
3296 && lyp_check_mandatory((struct lys_node *)aug)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003297 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, "mandatory", "augment node");
3298 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 +01003299 return -1;
3300 }
3301
Michal Vasko07e89ef2016-03-03 13:28:57 +01003302 /* check augment target type and then augment nodes type */
3303 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
3304 LY_TREE_FOR(aug->child, sub) {
3305 if (!(sub->nodetype & (LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003306 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3307 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003308 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3309 return -1;
3310 }
3311 }
3312 } else if (aug->target->nodetype == LYS_CHOICE) {
3313 LY_TREE_FOR(aug->child, sub) {
3314 if (!(sub->nodetype & (LYS_CASE | LYS_ANYXML | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003315 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
3316 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko07e89ef2016-03-03 13:28:57 +01003317 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
3318 return -1;
3319 }
3320 }
3321 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003322 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
3323 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01003324 return -1;
3325 }
3326
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003327 /* inherit config information from parent, augment does not have
3328 * config property, but we need to keep the information for subelements
3329 */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003330 aug->flags |= aug->target->flags & LYS_CONFIG_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003331 LY_TREE_FOR(aug->child, sub) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003332 inherit_config_flag(sub);
3333 }
3334
Radek Krejcic071c542016-01-27 14:57:51 +01003335 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02003336 LY_TREE_FOR(aug->child, sub) {
Michal Vasko4f0dad02016-02-15 14:08:23 +01003337 if (lys_check_id(sub, aug->parent, lys_module(aug->module))) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02003338 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02003339 }
3340 }
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003341 /* reconnect augmenting data into the target - add them to the target child list */
3342 if (aug->target->child) {
Michal Vasko1d87a922015-08-21 12:57:16 +02003343 sub = aug->target->child->prev; /* remember current target's last node */
3344 sub->next = aug->child; /* connect augmenting data after target's last node */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003345 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
Michal Vasko1d87a922015-08-21 12:57:16 +02003346 aug->child->prev = sub; /* finish connecting of both child lists */
Radek Krejci0acbe1b2015-08-04 09:33:49 +02003347 } else {
3348 aug->target->child = aug->child;
3349 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003350
3351 return EXIT_SUCCESS;
3352}
3353
Michal Vasko730dfdf2015-08-11 14:48:05 +02003354/**
3355 * @brief Resolve uses, apply augments, refines. Logs directly.
3356 *
Michal Vaskobb211122015-08-19 14:03:11 +02003357 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003358 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003359 *
Michal Vaskodef0db12015-10-07 13:22:48 +02003360 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003361 */
Michal Vasko184521f2015-09-24 13:14:26 +02003362static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003363resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003364{
3365 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003366 struct lys_node *node = NULL;
3367 const struct lys_node *node_aux;
Radek Krejci76512572015-08-04 09:47:08 +02003368 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003369 struct lys_restr *must, **old_must;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003370 int i, j, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003371 uint8_t size, *old_size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372
Michal Vasko71e1aa82015-08-12 12:17:51 +02003373 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01003374 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02003375 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02003376
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01003378 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskod51d6ad2016-02-16 13:24:31 +01003379 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 +01003380 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003381 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
3382 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003383 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003385 }
3386 ctx = uses->module->ctx;
3387
Michal Vaskodef0db12015-10-07 13:22:48 +02003388 /* we managed to copy the grouping, the rest must be possible to resolve */
3389
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003390 /* apply refines */
3391 for (i = 0; i < uses->refine_size; i++) {
3392 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01003393 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
3394 (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003395 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003396 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskodef0db12015-10-07 13:22:48 +02003397 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003398 }
3399
Radek Krejci1d82ef62015-08-07 14:44:40 +02003400 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003401 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
3402 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003403 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405
3406 /* description on any nodetype */
3407 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003408 lydict_remove(ctx, node->dsc);
3409 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 }
3411
3412 /* reference on any nodetype */
3413 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003414 lydict_remove(ctx, node->ref);
3415 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003416 }
3417
3418 /* config on any nodetype */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003419 if (rfn->flags & LYS_CONFIG_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003420 node->flags &= ~LYS_CONFIG_MASK;
3421 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003422 }
3423
3424 /* default value ... */
3425 if (rfn->mod.dflt) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003426 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 /* leaf */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003428 lydict_remove(ctx, ((struct lys_node_leaf *)node)->dflt);
3429 ((struct lys_node_leaf *)node)->dflt = lydict_insert(ctx, rfn->mod.dflt, 0);
3430 } else if (node->nodetype == LYS_CHOICE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003431 /* choice */
Michal Vasko3edeaf72016-02-11 13:17:43 +01003432 rc = resolve_choice_default_schema_nodeid(rfn->mod.dflt, node->child,
3433 (const struct lys_node **)&((struct lys_node_choice *)node)->dflt);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003434 if (rc || !((struct lys_node_choice *)node)->dflt) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003435 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->mod.dflt, "default");
Michal Vaskodef0db12015-10-07 13:22:48 +02003436 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003437 }
3438 }
3439 }
3440
3441 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02003442 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003443 if (node->nodetype & (LYS_LEAF | LYS_ANYXML | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003444 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003445 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003446
3447 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003448 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003449 }
3450 }
3451
3452 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003453 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
3454 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
3455 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456 }
3457
3458 /* min/max-elements on list or leaf-list */
3459 /* magic - bit 3 in flags means min set, bit 4 says max set */
Radek Krejci1d82ef62015-08-07 14:44:40 +02003460 if (node->nodetype == LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003461 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003462 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003463 }
3464 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003465 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003466 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02003467 } else if (node->nodetype == LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468 if (rfn->flags & 0x04) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003469 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 }
3471 if (rfn->flags & 0x08) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02003472 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473 }
3474 }
3475
3476 /* must in leaf, leaf-list, list, container or anyxml */
3477 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003478 switch (node->nodetype) {
3479 case LYS_LEAF:
3480 old_size = &((struct lys_node_leaf *)node)->must_size;
3481 old_must = &((struct lys_node_leaf *)node)->must;
3482 break;
3483 case LYS_LEAFLIST:
3484 old_size = &((struct lys_node_leaflist *)node)->must_size;
3485 old_must = &((struct lys_node_leaflist *)node)->must;
3486 break;
3487 case LYS_LIST:
3488 old_size = &((struct lys_node_list *)node)->must_size;
3489 old_must = &((struct lys_node_list *)node)->must;
3490 break;
3491 case LYS_CONTAINER:
3492 old_size = &((struct lys_node_container *)node)->must_size;
3493 old_must = &((struct lys_node_container *)node)->must;
3494 break;
3495 case LYS_ANYXML:
3496 old_size = &((struct lys_node_anyxml *)node)->must_size;
3497 old_must = &((struct lys_node_anyxml *)node)->must;
3498 break;
3499 default:
3500 LOGINT;
Radek Krejcie4e4d722015-10-05 16:53:50 +02003501 return -1;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003502 }
3503
3504 size = *old_size + rfn->must_size;
3505 must = realloc(*old_must, size * sizeof *rfn->must);
3506 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507 LOGMEM;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 }
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003510 for (i = 0, j = *old_size; i < rfn->must_size; i++, j++) {
3511 must[j].expr = lydict_insert(ctx, rfn->must[i].expr, 0);
3512 must[j].dsc = lydict_insert(ctx, rfn->must[i].dsc, 0);
3513 must[j].ref = lydict_insert(ctx, rfn->must[i].ref, 0);
3514 must[j].eapptag = lydict_insert(ctx, rfn->must[i].eapptag, 0);
3515 must[j].emsg = lydict_insert(ctx, rfn->must[i].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 }
3517
Michal Vaskoef2fdc82015-09-24 09:54:42 +02003518 *old_must = must;
3519 *old_size = size;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003520 }
3521 }
3522
3523 /* apply augments */
3524 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003525 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003526 if (rc) {
Michal Vaskodef0db12015-10-07 13:22:48 +02003527 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003528 }
3529 }
3530
3531 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532}
3533
Michal Vasko730dfdf2015-08-11 14:48:05 +02003534/**
3535 * @brief Resolve base identity recursively. Does not log.
3536 *
3537 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003538 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003539 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003540 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003541 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003542 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003543 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003544static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003545resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003546 struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547{
Michal Vaskof02e3742015-08-05 16:27:02 +02003548 uint32_t i, j;
Radek Krejcibabbff82016-02-19 13:31:37 +01003549 struct lys_ident *base = NULL, *base_iter;
Radek Krejcia52656e2015-08-05 13:41:50 +02003550 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003551
Radek Krejcicf509982015-12-15 09:22:44 +01003552 assert(ret);
3553
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554 /* search module */
3555 for (i = 0; i < module->ident_size; i++) {
3556 if (!strcmp(basename, module->ident[i].name)) {
3557
3558 if (!ident) {
3559 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003560 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01003561 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003562 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003563 }
3564
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003565 base = &module->ident[i];
3566 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 }
3568 }
3569
3570 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003571 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
3572 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
3573 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003574
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003575 if (!ident) {
3576 *ret = &module->inc[j].submodule->ident[i];
3577 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003579
3580 base = &module->inc[j].submodule->ident[i];
3581 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 }
3583 }
3584 }
3585
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01003586matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01003588 if (base) {
3589 /* check for circular reference */
3590 for (base_iter = base; base_iter; base_iter = base_iter->base) {
3591 if (ident == base_iter) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003592 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, base_iter->name, "base");
3593 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejcibabbff82016-02-19 13:31:37 +01003594 return EXIT_FAILURE;
3595 }
3596 }
3597 /* checks done, store the result */
3598 ident->base = base;
3599
3600 /* maintain backlinks to the derived identitise */
3601 while (base) {
3602 for (der = base->der; der && der->next; der = der->next);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003603 if (der) {
3604 der->next = malloc(sizeof *der);
3605 der = der->next;
3606 } else {
3607 ident->base->der = der = malloc(sizeof *der);
3608 }
Michal Vasko253035f2015-12-17 16:58:13 +01003609 if (!der) {
3610 LOGMEM;
3611 return EXIT_FAILURE;
3612 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003613 der->next = NULL;
3614 der->ident = ident;
3615
Radek Krejcibabbff82016-02-19 13:31:37 +01003616 base = base->base;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617 }
Radek Krejcicf509982015-12-15 09:22:44 +01003618 *ret = ident->base;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003619 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003620 }
3621
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003622 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623}
3624
Michal Vasko730dfdf2015-08-11 14:48:05 +02003625/**
3626 * @brief Resolve base identity. Logs directly.
3627 *
3628 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02003629 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003630 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01003631 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01003632 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003633 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003634 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003635 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003636static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003637resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char* parent,
Radek Krejci48464ed2016-03-17 15:44:09 +01003638 struct lys_type *type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639{
3640 const char *name;
Michal Vasko2d851a92015-10-20 16:16:36 +02003641 int i, mod_name_len = 0;
Radek Krejcicf509982015-12-15 09:22:44 +01003642 struct lys_ident *target, **ret;
3643 uint8_t flags;
3644 struct lys_module *mod;
3645
3646 assert((ident && !type) || (!ident && type));
3647
3648 if (!type) {
3649 /* have ident to resolve */
3650 ret = &target;
3651 flags = ident->flags;
3652 mod = ident->module;
3653 } else {
3654 /* have type to fill */
3655 ret = &type->info.ident.ref;
3656 flags = type->parent->flags;
3657 mod = type->parent->module;
3658 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003659
3660 /* search for the base identity */
3661 name = strchr(basename, ':');
3662 if (name) {
3663 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02003664 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003665 name++;
3666
Michal Vasko2d851a92015-10-20 16:16:36 +02003667 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003668 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02003669 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003670 }
3671 } else {
3672 name = basename;
3673 }
3674
Radek Krejcic071c542016-01-27 14:57:51 +01003675 /* get module where to search */
3676 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
3677 if (!module) {
3678 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01003679 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01003680 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003681 }
3682
Radek Krejcic071c542016-01-27 14:57:51 +01003683 /* search in the identified module ... */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003684 if (!resolve_base_ident_sub(module, ident, name, ret)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003685 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003686 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003687 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003688 }
Radek Krejcic071c542016-01-27 14:57:51 +01003689 /* and all its submodules */
3690 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
3691 if (!resolve_base_ident_sub((struct lys_module *)module->inc[i].submodule, ident, name, ret)) {
3692 goto success;
Radek Krejcibabbff82016-02-19 13:31:37 +01003693 } else if (ly_errno) {
Radek Krejcibabbff82016-02-19 13:31:37 +01003694 return EXIT_FAILURE;
Radek Krejcic071c542016-01-27 14:57:51 +01003695 }
3696 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003697
Radek Krejci02a04992016-03-17 16:06:37 +01003698 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, parent);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003699 return EXIT_FAILURE;
Radek Krejcicf509982015-12-15 09:22:44 +01003700
3701success:
3702 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003703 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
3704 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003705 return -1;
3706 }
3707
3708 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003709}
3710
Michal Vasko730dfdf2015-08-11 14:48:05 +02003711/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003712 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003713 *
3714 * @param[in] base Base identity.
Michal Vaskofb0873c2015-08-21 09:00:07 +02003715 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01003716 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003717 *
3718 * @return Pointer to the identity resolvent, NULL on error.
3719 */
Radek Krejcia52656e2015-08-05 13:41:50 +02003720struct lys_ident *
Radek Krejci48464ed2016-03-17 15:44:09 +01003721resolve_identref(struct lys_ident *base, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003722{
Michal Vaskoc633ca02015-08-21 14:03:51 +02003723 const char *mod_name, *name;
3724 int mod_name_len, rc;
Radek Krejcia52656e2015-08-05 13:41:50 +02003725 struct lys_ident_der *der;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726
Michal Vaskofb0873c2015-08-21 09:00:07 +02003727 if (!base || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003728 return NULL;
3729 }
3730
Michal Vaskoc633ca02015-08-21 14:03:51 +02003731 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003732 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003733 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003734 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01003735 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01003736 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02003737 return NULL;
3738 }
3739
Michal Vaskoc633ca02015-08-21 14:03:51 +02003740 if (!strcmp(base->name, name) && (!mod_name
3741 || (!strncmp(base->module->name, mod_name, mod_name_len) && !base->module->name[mod_name_len]))) {
Michal Vaskofb0873c2015-08-21 09:00:07 +02003742 return base;
3743 }
3744
3745 for (der = base->der; der; der = der->next) {
Michal Vaskoc633ca02015-08-21 14:03:51 +02003746 if (!strcmp(der->ident->name, name) && (!mod_name
3747 || (!strncmp(der->ident->module->name, mod_name, mod_name_len)
3748 && !der->ident->module->name[mod_name_len]))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003749 /* we have match */
3750 return der->ident;
3751 }
3752 }
3753
Radek Krejci48464ed2016-03-17 15:44:09 +01003754 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003755 return NULL;
3756}
3757
Michal Vasko730dfdf2015-08-11 14:48:05 +02003758/**
Michal Vasko7955b362015-09-04 14:18:15 +02003759 * @brief Resolve (find) choice default case. Does not log.
3760 *
3761 * @param[in] choic Choice to use.
3762 * @param[in] dflt Name of the default case.
3763 *
3764 * @return Pointer to the default node or NULL.
3765 */
3766static struct lys_node *
3767resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
3768{
3769 struct lys_node *child, *ret;
3770
3771 LY_TREE_FOR(choic->child, child) {
3772 if (child->nodetype == LYS_USES) {
3773 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
3774 if (ret) {
3775 return ret;
3776 }
3777 }
3778
Radek Krejci749190d2016-02-18 16:26:25 +01003779 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYXML | LYS_CASE
Michal Vasko7955b362015-09-04 14:18:15 +02003780 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
3781 return child;
3782 }
3783 }
3784
3785 return NULL;
3786}
3787
3788/**
Michal Vaskobb211122015-08-19 14:03:11 +02003789 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003790 *
Michal Vaskobb211122015-08-19 14:03:11 +02003791 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003792 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003793 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003794 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003795 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003796static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003797resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003798{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003799 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01003800 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02003801
Radek Krejci010e54b2016-03-15 09:40:34 +01003802 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
3803 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
3804 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
3805 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
3806 * LYS_USESGRP flag is used. */
3807 for (par_grp = uses->parent; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = par_grp->parent);
Michal Vaskoe91afce2015-08-12 12:21:00 +02003808
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003809 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01003810 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
3811 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003812 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003813 return -1;
3814 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003815 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01003816 return -1;
3817 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003818 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3819 par_grp->nacm++;
3820 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003821 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01003822 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02003823 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003824 }
3825
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003826 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003827 if (par_grp && !(uses->flags & LYS_USESGRP)) {
3828 par_grp->nacm++;
3829 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02003830 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003831 return EXIT_FAILURE;
3832 }
3833
Radek Krejci48464ed2016-03-17 15:44:09 +01003834 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003835 if (!rc) {
3836 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01003837 if (par_grp && (uses->flags & LYS_USESGRP)) {
3838 if (!par_grp->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003839 LOGINT;
3840 return -1;
3841 }
Radek Krejci010e54b2016-03-15 09:40:34 +01003842 par_grp->nacm--;
3843 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003844 }
Radek Krejcicf509982015-12-15 09:22:44 +01003845
3846 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003847 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01003848 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003849 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003850 return -1;
3851 }
3852
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003853 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01003854 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
3855 par_grp->nacm++;
3856 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003857 }
3858
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003859 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003860}
3861
Michal Vasko730dfdf2015-08-11 14:48:05 +02003862/**
Michal Vasko9957e592015-08-17 15:04:09 +02003863 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003864 *
Michal Vaskobb211122015-08-19 14:03:11 +02003865 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003866 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003867 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003868 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003869 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003870static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003871resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003872{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003873 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003874 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003875
3876 for (i = 0; i < list->keys_size; ++i) {
3877 /* get the key name */
3878 if ((value = strpbrk(keys_str, " \t\n"))) {
3879 len = value - keys_str;
3880 while (isspace(value[0])) {
3881 value++;
3882 }
3883 } else {
3884 len = strlen(keys_str);
3885 }
3886
Michal Vasko4f0dad02016-02-15 14:08:23 +01003887 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 +02003888 if (rc) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003889 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003890 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003891 }
3892 return rc;
3893 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003894
Radek Krejci48464ed2016-03-17 15:44:09 +01003895 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003896 /* check_key logs */
3897 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003898 }
3899
Radek Krejcicf509982015-12-15 09:22:44 +01003900 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01003901 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003902 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
3903 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01003904 return -1;
3905 }
3906
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003907 /* prepare for next iteration */
3908 while (value && isspace(value[0])) {
3909 value++;
3910 }
3911 keys_str = value;
3912 }
3913
Michal Vaskof02e3742015-08-05 16:27:02 +02003914 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003915}
3916
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003917/**
Michal Vaskobf19d252015-10-08 15:39:17 +02003918 * @brief Resolve (check) all must conditions of \p node.
3919 * Logs directly.
3920 *
3921 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02003922 *
3923 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
3924 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003925static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003926resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02003927{
Michal Vaskobf19d252015-10-08 15:39:17 +02003928 uint8_t i, must_size;
3929 struct lys_restr *must;
3930 struct lyxp_set set;
3931
3932 assert(node);
3933 memset(&set, 0, sizeof set);
3934
3935 switch (node->schema->nodetype) {
3936 case LYS_CONTAINER:
3937 must_size = ((struct lys_node_container *)node->schema)->must_size;
3938 must = ((struct lys_node_container *)node->schema)->must;
3939 break;
3940 case LYS_LEAF:
3941 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
3942 must = ((struct lys_node_leaf *)node->schema)->must;
3943 break;
3944 case LYS_LEAFLIST:
3945 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
3946 must = ((struct lys_node_leaflist *)node->schema)->must;
3947 break;
3948 case LYS_LIST:
3949 must_size = ((struct lys_node_list *)node->schema)->must_size;
3950 must = ((struct lys_node_list *)node->schema)->must;
3951 break;
3952 case LYS_ANYXML:
3953 must_size = ((struct lys_node_anyxml *)node->schema)->must_size;
3954 must = ((struct lys_node_anyxml *)node->schema)->must;
3955 break;
3956 default:
3957 must_size = 0;
3958 break;
3959 }
3960
3961 for (i = 0; i < must_size; ++i) {
Michal Vasko944a5642016-03-21 11:48:58 +01003962 if (lyxp_eval(must[i].expr, node, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02003963 return -1;
3964 }
3965
Michal Vasko944a5642016-03-21 11:48:58 +01003966 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02003967
3968 if (!set.value.bool) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003969 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "Must", must[i].expr);
Michal Vaskobf19d252015-10-08 15:39:17 +02003970 return 1;
3971 }
3972 }
3973
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003974 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02003975}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003976
Michal Vaskobf19d252015-10-08 15:39:17 +02003977/**
Michal Vaskocf024702015-10-08 15:01:42 +02003978 * @brief Resolve (find) when condition context node. Does not log.
3979 *
3980 * @param[in] node Data node, whose conditional definition is being decided.
3981 * @param[in] schema Schema node with a when condition.
3982 *
3983 * @return Context node.
3984 */
3985static struct lyd_node *
3986resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003987{
Michal Vaskocf024702015-10-08 15:01:42 +02003988 struct lyd_node *parent;
3989 struct lys_node *sparent;
3990 uint16_t i, data_depth, schema_depth;
3991
3992 /* find a not schema-only node */
3993 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
3994 schema = lys_parent(schema);
3995 if (!schema) {
3996 return NULL;
3997 }
3998 }
3999
4000 /* get node depths */
4001 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
4002 for (sparent = lys_parent(schema), schema_depth = 1; sparent; sparent = lys_parent(sparent)) {
4003 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYXML | LYS_NOTIF | LYS_RPC)) {
4004 ++schema_depth;
4005 }
4006 }
4007 if (data_depth < schema_depth) {
4008 return NULL;
4009 }
4010
4011 /* find the corresponding data node */
4012 for (i = 0; i < data_depth - schema_depth; ++i) {
4013 node = node->parent;
4014 }
4015 if (node->schema != schema) {
4016 return NULL;
4017 }
4018
4019 return node;
4020}
4021
Radek Krejci03b71f72016-03-16 11:10:09 +01004022int
Radek Krejci01696bf2016-03-18 13:19:36 +01004023resolve_applies_must(const struct lyd_node *node)
4024{
4025 switch (node->schema->nodetype) {
4026 case LYS_CONTAINER:
4027 return ((struct lys_node_container *)node->schema)->must_size;
4028 case LYS_LEAF:
4029 return ((struct lys_node_leaf *)node->schema)->must_size;
4030 case LYS_LEAFLIST:
4031 return ((struct lys_node_leaflist *)node->schema)->must_size;
4032 case LYS_LIST:
4033 return ((struct lys_node_list *)node->schema)->must_size;
4034 case LYS_ANYXML:
4035 return ((struct lys_node_anyxml *)node->schema)->must_size;
4036 default:
4037 return 0;
4038 }
4039}
4040
4041int
Radek Krejci03b71f72016-03-16 11:10:09 +01004042resolve_applies_when(const struct lyd_node *node)
4043{
4044 struct lys_node *parent;
4045
4046 assert(node);
4047
4048 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
4049 return 1;
4050 }
4051
4052 parent = node->schema;
4053 goto check_augment;
4054
4055 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4056 if (((struct lys_node_uses *)parent)->when) {
4057 return 1;
4058 }
4059check_augment:
4060
4061 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
4062 (((struct lys_node_augment *)parent->parent)->when))) {
4063
4064 }
4065 parent = lys_parent(parent);
4066 }
4067
4068 return 0;
4069}
4070
Michal Vaskocf024702015-10-08 15:01:42 +02004071/**
4072 * @brief Resolve (check) all when conditions relevant for \p node.
4073 * Logs directly.
4074 *
4075 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02004076 *
Radek Krejci03b71f72016-03-16 11:10:09 +01004077 * @return
4078 * -1 - error, ly_errno is set
4079 * 0 - true "when" statement
4080 * 0, ly_vecode = LYVE_NOCOND - false "when" statement
4081 * 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 +02004082 */
4083static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004084resolve_when(struct lyd_node *node)
Michal Vaskocf024702015-10-08 15:01:42 +02004085{
4086 struct lyd_node *ctx_node = NULL;
4087 struct lys_node *parent;
4088 struct lyxp_set set;
Radek Krejci51093642016-03-29 10:14:59 +02004089 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02004090
4091 assert(node);
4092 memset(&set, 0, sizeof set);
4093
4094 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko944a5642016-03-21 11:48:58 +01004095 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004096 if (rc) {
4097 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004098 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004099 }
Radek Krejci51093642016-03-29 10:14:59 +02004100 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004101 }
4102
Radek Krejci03b71f72016-03-16 11:10:09 +01004103 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01004104 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004105 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004106 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004107 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004108 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004109 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004110 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004111 }
Radek Krejci51093642016-03-29 10:14:59 +02004112
4113 /* free xpath set content */
4114 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004115 }
4116
4117 parent = node->schema;
4118 goto check_augment;
4119
4120 /* check when in every schema node that affects node */
4121 while (parent && (parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
4122 if (((struct lys_node_uses *)parent)->when) {
4123 if (!ctx_node) {
4124 ctx_node = resolve_when_ctx_node(node, parent);
4125 if (!ctx_node) {
4126 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004127 rc = -1;
4128 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004129 }
4130 }
Michal Vasko944a5642016-03-21 11:48:58 +01004131 rc = lyxp_eval(((struct lys_node_uses *)parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004132 if (rc) {
4133 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004134 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004135 }
Radek Krejci51093642016-03-29 10:14:59 +02004136 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004137 }
4138
Michal Vasko944a5642016-03-21 11:48:58 +01004139 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004140 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004141 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004142 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_uses *)parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004143 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004144 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004145 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004146 }
Radek Krejci51093642016-03-29 10:14:59 +02004147
4148 /* free xpath set content */
4149 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004150 }
4151
4152check_augment:
4153 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)parent->parent)->when))) {
4154 if (!ctx_node) {
4155 ctx_node = resolve_when_ctx_node(node, parent->parent);
4156 if (!ctx_node) {
4157 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02004158 rc = -1;
4159 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004160 }
4161 }
Michal Vasko944a5642016-03-21 11:48:58 +01004162 rc = lyxp_eval(((struct lys_node_augment *)parent->parent)->when->cond, ctx_node, &set, LYXP_WHEN);
Radek Krejci03b71f72016-03-16 11:10:09 +01004163 if (rc) {
4164 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004165 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004166 }
Radek Krejci51093642016-03-29 10:14:59 +02004167 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004168 }
4169
Michal Vasko944a5642016-03-21 11:48:58 +01004170 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02004171
4172 if (!set.value.bool) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004173 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004174 LOGVAL(LYE_NOCOND, LY_VLOG_LYD, node, "When", ((struct lys_node_augment *)parent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01004175 ly_vlog_hide(0);
Radek Krejci0b7704f2016-03-18 12:16:14 +01004176 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02004177 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02004178 }
Radek Krejci51093642016-03-29 10:14:59 +02004179
4180 /* free xpath set content */
4181 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02004182 }
4183
4184 parent = lys_parent(parent);
4185 }
4186
Radek Krejci0b7704f2016-03-18 12:16:14 +01004187 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01004188
Radek Krejci51093642016-03-29 10:14:59 +02004189cleanup:
4190
4191 /* free xpath set content */
4192 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
4193
4194 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004195}
4196
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004197/**
Michal Vaskobb211122015-08-19 14:03:11 +02004198 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004199 *
4200 * @param[in] mod Main module.
4201 * @param[in] item Item to resolve. Type determined by \p type.
4202 * @param[in] type Type of the unresolved item.
4203 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02004204 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004205 *
4206 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4207 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004208static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004209resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01004210 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004211{
Radek Krejci4f78b532016-02-17 13:43:00 +01004212 int rc = -1, has_str = 0, tpdf_flag = 0;
Michal Vasko563ef092015-09-04 13:17:23 +02004213 struct lys_node *node;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004214 const char *base_name;
4215
4216 struct lys_ident *ident;
4217 struct lys_type *stype;
4218 struct lys_feature **feat_ptr;
4219 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01004220 struct lyxml_elem *yin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221
4222 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004223 case UNRES_IDENT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004224 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004225 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004226 ident = item;
4227
Radek Krejci48464ed2016-03-17 15:44:09 +01004228 rc = resolve_base_ident(mod, ident, base_name, "identity", NULL);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229 break;
4230 case UNRES_TYPE_IDENTREF:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004231 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004232 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004233 stype = item;
4234
Radek Krejci48464ed2016-03-17 15:44:09 +01004235 rc = resolve_base_ident(mod, NULL, base_name, "type", stype);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004236 break;
4237 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02004238 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004239 stype = item;
4240
Radek Krejci2f12f852016-01-08 12:59:57 +01004241 /* HACK - when there is no parent, we are in top level typedef and in that
4242 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
4243 * know it via tpdf_flag */
4244 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01004245 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01004246 node = (struct lys_node *)stype->parent;
4247 }
4248
Radek Krejci48464ed2016-03-17 15:44:09 +01004249 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01004250 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01004251 if (stype->info.lref.target) {
4252 /* store the backlink from leafref target */
4253 if (!stype->info.lref.target->child) {
4254 stype->info.lref.target->child = (void*)ly_set_new();
4255 if (!stype->info.lref.target->child) {
4256 LOGMEM;
4257 return -1;
4258 }
4259 }
4260 ly_set_add((struct ly_set *)stype->info.lref.target->child, stype->parent);
4261 }
4262
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004263 break;
4264 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01004265 /* parent */
4266 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004267 stype = item;
4268
Michal Vasko88c29542015-11-27 14:57:53 +01004269 /* HACK type->der is temporarily unparsed type statement */
4270 yin = (struct lyxml_elem *)stype->der;
4271 stype->der = NULL;
4272
4273 rc = fill_yin_type(mod, node, yin, stype, unres);
4274 if (!rc) {
4275 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko345da0a2015-12-02 10:35:55 +01004276 lyxml_free(mod->ctx, yin);
Michal Vasko88c29542015-11-27 14:57:53 +01004277 } else {
4278 /* may try again later, put all back how it was */
4279 stype->der = (struct lys_tpdf *)yin;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004280 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004281 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004282 case UNRES_IFFEAT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004283 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004284 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004285 feat_ptr = item;
4286
Radek Krejci48464ed2016-03-17 15:44:09 +01004287 rc = resolve_feature(base_name, mod, feat_ptr);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004288 break;
4289 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004290 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004291 break;
4292 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004293 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004294 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004295 stype = item;
4296
Radek Krejci48464ed2016-03-17 15:44:09 +01004297 rc = check_default(stype, base_name, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004298 break;
4299 case UNRES_CHOICE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004300 base_name = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01004301 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004302 choic = item;
4303
Michal Vasko7955b362015-09-04 14:18:15 +02004304 choic->dflt = resolve_choice_dflt(choic, base_name);
4305 if (choic->dflt) {
4306 rc = EXIT_SUCCESS;
4307 } else {
4308 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02004309 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004310 break;
4311 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01004312 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004313 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004314 break;
4315 case UNRES_LIST_UNIQ:
Radek Krejci4f78b532016-02-17 13:43:00 +01004316 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01004317 rc = resolve_unique(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004319 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004320 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01004321 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004322 default:
4323 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004324 break;
4325 }
4326
Radek Krejci4f78b532016-02-17 13:43:00 +01004327 if (has_str && !rc) {
4328 lydict_remove(mod->ctx, str_snode);
4329 }
4330
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004331 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004332}
4333
Michal Vaskof02e3742015-08-05 16:27:02 +02004334/* logs directly */
4335static void
Radek Krejci48464ed2016-03-17 15:44:09 +01004336print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004337{
Michal Vaskof02e3742015-08-05 16:27:02 +02004338 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02004339 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004340 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004341 break;
4342 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004343 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004344 break;
4345 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01004346 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
4347 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02004348 break;
4349 case UNRES_TYPE_DER:
Radek Krejci48464ed2016-03-17 15:44:09 +01004350 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type",
4351 ((struct lyxml_elem *)((struct lys_type *)item)->der)->attr->value);
Michal Vaskof02e3742015-08-05 16:27:02 +02004352 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02004353 case UNRES_IFFEAT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004354 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004355 break;
4356 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01004357 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02004358 break;
4359 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004360 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004361 break;
4362 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004363 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004364 break;
4365 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01004366 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004367 break;
4368 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01004369 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02004370 break;
Michal Vasko7178e692016-02-12 15:58:05 +01004371 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01004372 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
4373 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01004374 break;
Michal Vaskocf024702015-10-08 15:01:42 +02004375 default:
4376 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02004377 break;
4378 }
4379}
4380
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004381/**
Michal Vaskobb211122015-08-19 14:03:11 +02004382 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004383 *
4384 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004385 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004386 *
Michal Vasko92b8a382015-08-19 14:03:49 +02004387 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004388 */
Michal Vaskof02e3742015-08-05 16:27:02 +02004389int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004390resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02004391{
Radek Krejci010e54b2016-03-15 09:40:34 +01004392 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004393 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004394
4395 assert(unres);
4396
Radek Krejci010e54b2016-03-15 09:40:34 +01004397 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4398 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02004399
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004400 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02004401 do {
Michal Vasko88c29542015-11-27 14:57:53 +01004402 unres_count = 0;
4403 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02004404
4405 for (i = 0; i < unres->count; ++i) {
Michal Vasko88c29542015-11-27 14:57:53 +01004406 /* we do not need to have UNRES_TYPE_IDENTREF or UNRES_TYPE_LEAFREF resolved,
4407 * we need every type's base only */
4408 if ((unres->type[i] != UNRES_USES) && (unres->type[i] != UNRES_TYPE_DER)) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004409 continue;
4410 }
4411
Michal Vasko88c29542015-11-27 14:57:53 +01004412 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01004413 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004414 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02004415 unres->type[i] = UNRES_RESOLVED;
4416 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01004417 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02004418 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004419 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004420 return -1;
Michal Vasko51054ca2015-08-12 12:20:00 +02004421 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004422 }
Michal Vasko88c29542015-11-27 14:57:53 +01004423 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02004424
Michal Vasko88c29542015-11-27 14:57:53 +01004425 if (res_count < unres_count) {
Michal Vasko92b8a382015-08-19 14:03:49 +02004426 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004427 }
4428
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004429 /* the rest */
4430 for (i = 0; i < unres->count; ++i) {
4431 if (unres->type[i] == UNRES_RESOLVED) {
4432 continue;
4433 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02004434
Radek Krejci48464ed2016-03-17 15:44:09 +01004435 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004436 if (rc == 0) {
4437 unres->type[i] = UNRES_RESOLVED;
4438 ++resolved;
4439 } else if (rc == -1) {
4440 ly_vlog_hide(0);
Michal Vasko184521f2015-09-24 13:14:26 +02004441 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004442 }
4443 }
4444
Radek Krejci010e54b2016-03-15 09:40:34 +01004445 ly_vlog_hide(0);
4446
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004447 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004448 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
4449 * all the validation errors
4450 */
4451 for (i = 0; i < unres->count; ++i) {
4452 if (unres->type[i] == UNRES_RESOLVED) {
4453 continue;
4454 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004455 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004456 }
Michal Vasko92b8a382015-08-19 14:03:49 +02004457 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004458 }
4459
Radek Krejci010e54b2016-03-15 09:40:34 +01004460 LOGVRB("Resolving unresolved schema nodes and their constraints.");
4461
Radek Krejcic071c542016-01-27 14:57:51 +01004462 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004463 return EXIT_SUCCESS;
4464}
4465
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004466/**
Michal Vaskobb211122015-08-19 14:03:11 +02004467 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004468 *
4469 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004470 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004471 * @param[in] item Item to resolve. Type determined by \p type.
4472 * @param[in] type Type of the unresolved item.
4473 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004474 *
4475 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4476 */
4477int
Radek Krejci48464ed2016-03-17 15:44:09 +01004478unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
4479 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004480{
Radek Krejci48464ed2016-03-17 15:44:09 +01004481 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 +02004482}
4483
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004484/**
Michal Vaskobb211122015-08-19 14:03:11 +02004485 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004486 *
4487 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004488 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004489 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01004490 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004491 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004492 *
4493 * @return EXIT_SUCCESS on success or storing the item in unres, -1 on error.
4494 */
4495int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004496unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01004497 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004498{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004499 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01004500 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01004501 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004502
Michal Vasko9bf425b2015-10-22 11:42:03 +02004503 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
4504 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004505
Radek Krejci010e54b2016-03-15 09:40:34 +01004506 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01004507 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01004508 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004509 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004510 if (rc == -1 && ly_errno == LY_EVALID) {
4511 path = strdup(ly_errpath());
4512 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()),
4513 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
4514 free(path);
4515 free(msg);
4516 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004517 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004518 }
4519
Radek Krejci48464ed2016-03-17 15:44:09 +01004520 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02004521
Michal Vasko88c29542015-11-27 14:57:53 +01004522 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
4523 if (type == UNRES_TYPE_DER) {
4524 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
4525 lyxml_unlink_elem(mod->ctx, yin, 1);
4526 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
4527 }
4528
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004529 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004530 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
4531 if (!unres->item) {
4532 LOGMEM;
4533 return -1;
4534 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004535 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01004536 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
4537 if (!unres->type) {
4538 LOGMEM;
4539 return -1;
4540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004541 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01004542 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
4543 if (!unres->str_snode) {
4544 LOGMEM;
4545 return -1;
4546 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004547 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01004548 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
4549 if (!unres->module) {
4550 LOGMEM;
4551 return -1;
4552 }
4553 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004554
4555 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556}
4557
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004558/**
Michal Vaskobb211122015-08-19 14:03:11 +02004559 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004560 *
4561 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004562 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004563 * @param[in] item Old item to be resolved.
4564 * @param[in] type Type of the old unresolved item.
4565 * @param[in] new_item New item to use in the duplicate.
4566 *
4567 * @return EXIT_SUCCESS on success, -1 on error.
4568 */
Michal Vaskodad19402015-08-06 09:51:53 +02004569int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004570unres_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 +02004571{
4572 int i;
4573
Michal Vaskocf024702015-10-08 15:01:42 +02004574 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004575
Michal Vasko0bd29d12015-08-19 11:45:49 +02004576 i = unres_schema_find(unres, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004577
4578 if (i == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004579 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004580 }
4581
Michal Vasko0d204592015-10-07 09:50:04 +02004582 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004583 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004584 LOGINT;
4585 return -1;
4586 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004587 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004588 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004589 LOGINT;
4590 return -1;
4591 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004592 }
Michal Vaskodad19402015-08-06 09:51:53 +02004593
4594 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004595}
4596
Michal Vaskof02e3742015-08-05 16:27:02 +02004597/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004598int
Michal Vasko0bd29d12015-08-19 11:45:49 +02004599unres_schema_find(struct unres_schema *unres, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004600{
4601 uint32_t ret = -1, i;
4602
4603 for (i = 0; i < unres->count; ++i) {
4604 if ((unres->item[i] == item) && (unres->type[i] == type)) {
4605 ret = i;
4606 break;
4607 }
4608 }
4609
4610 return ret;
4611}
Michal Vasko8bcdf292015-08-19 14:04:43 +02004612
Michal Vasko88c29542015-11-27 14:57:53 +01004613void
Radek Krejcic071c542016-01-27 14:57:51 +01004614unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01004615{
4616 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01004617 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01004618
Radek Krejcic071c542016-01-27 14:57:51 +01004619 if (!unres || !(*unres)) {
4620 return;
Michal Vasko88c29542015-11-27 14:57:53 +01004621 }
4622
Radek Krejcic071c542016-01-27 14:57:51 +01004623 assert(module || (*unres)->count == 0);
4624
4625 for (i = 0; i < (*unres)->count; ++i) {
4626 if ((*unres)->module[i] != module) {
4627 if ((*unres)->type[i] != UNRES_RESOLVED) {
4628 unresolved++;
4629 }
4630 continue;
4631 }
4632 if ((*unres)->type[i] == UNRES_TYPE_DER) {
4633 lyxml_free(module->ctx, (struct lyxml_elem *)((struct lys_type *)(*unres)->item[i])->der);
4634 }
4635 (*unres)->type[i] = UNRES_RESOLVED;
4636 }
4637
4638 if (!module || (!unresolved && !module->type)) {
4639 free((*unres)->item);
4640 free((*unres)->type);
4641 free((*unres)->str_snode);
4642 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01004643 free((*unres));
4644 (*unres) = NULL;
4645 }
Michal Vasko88c29542015-11-27 14:57:53 +01004646}
4647
Michal Vasko8bcdf292015-08-19 14:04:43 +02004648/**
4649 * @brief Resolve a single unres data item. Logs directly.
4650 *
Michal Vaskocf024702015-10-08 15:01:42 +02004651 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02004652 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004653 *
4654 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4655 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02004656int
Radek Krejci48464ed2016-03-17 15:44:09 +01004657resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004658{
4659 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02004660 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02004661 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004662 struct lys_node_leaf *sleaf;
4663 struct unres_data matches;
4664
4665 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02004666 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02004667 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004668
Michal Vaskocf024702015-10-08 15:01:42 +02004669 switch (type) {
4670 case UNRES_LEAFREF:
4671 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci48464ed2016-03-17 15:44:09 +01004672 if ((rc = resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches))) {
Michal Vasko0491ab32015-08-19 14:28:29 +02004673 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004674 }
4675
4676 /* check that value matches */
4677 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01004678 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02004679 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02004680 break;
4681 }
4682 }
4683
Michal Vaskocf024702015-10-08 15:01:42 +02004684 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004685 memset(&matches, 0, sizeof matches);
4686
Michal Vaskocf024702015-10-08 15:01:42 +02004687 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004688 /* reference not found */
Radek Krejci48464ed2016-03-17 15:44:09 +01004689 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path);
4690 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 +02004691 return EXIT_FAILURE;
4692 }
Michal Vaskocf024702015-10-08 15:01:42 +02004693 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004694
Michal Vaskocf024702015-10-08 15:01:42 +02004695 case UNRES_INSTID:
4696 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004697 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01004698 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01004699 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02004700 if (ly_errno) {
4701 return -1;
4702 } else if (sleaf->type.info.inst.req > -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004703 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004704 return EXIT_FAILURE;
4705 } else {
Radek Krejci4ce42be2016-02-03 13:04:41 +01004706 LOGVRB("There is no instance of \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02004707 }
4708 }
Michal Vaskocf024702015-10-08 15:01:42 +02004709 break;
4710
4711 case UNRES_WHEN:
Radek Krejci48464ed2016-03-17 15:44:09 +01004712 if ((rc = resolve_when(node))) {
Michal Vaskocf024702015-10-08 15:01:42 +02004713 return rc;
4714 }
4715 break;
4716
Michal Vaskobf19d252015-10-08 15:39:17 +02004717 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01004718 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004719 return rc;
4720 }
4721 break;
4722
Michal Vaskocf024702015-10-08 15:01:42 +02004723 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02004724 LOGINT;
4725 return -1;
4726 }
4727
4728 return EXIT_SUCCESS;
4729}
4730
4731/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01004732 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02004733 *
4734 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02004735 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004736 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01004737 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02004738 */
4739int
Radek Krejci0b7704f2016-03-18 12:16:14 +01004740unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02004741{
Radek Krejci03b71f72016-03-16 11:10:09 +01004742 assert(unres && node);
4743 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST));
Michal Vasko8bcdf292015-08-19 14:04:43 +02004744
Radek Krejci03b71f72016-03-16 11:10:09 +01004745 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01004746 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
4747 if (!unres->node) {
4748 LOGMEM;
4749 return -1;
4750 }
Michal Vaskocf024702015-10-08 15:01:42 +02004751 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01004752 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
4753 if (!unres->type) {
4754 LOGMEM;
4755 return -1;
4756 }
Michal Vaskocf024702015-10-08 15:01:42 +02004757 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02004758
Radek Krejci0b7704f2016-03-18 12:16:14 +01004759 if (type == UNRES_WHEN) {
4760 /* remove previous result */
4761 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004762 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004763
4764 return EXIT_SUCCESS;
4765}
4766
4767/**
4768 * @brief Resolve every unres data item in the structure. Logs directly.
4769 *
4770 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01004771 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
4772 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01004773 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004774 *
4775 * @return EXIT_SUCCESS on success, -1 on error.
4776 */
4777int
Radek Krejci0c0086a2016-03-24 15:20:28 +01004778resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004779{
Radek Krejci0c0086a2016-03-24 15:20:28 +01004780 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01004781 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01004782 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004783 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004784
Radek Krejci03b71f72016-03-16 11:10:09 +01004785 assert(unres);
4786 assert(root && (*root));
4787
4788 if (!unres->count) {
4789 return EXIT_SUCCESS;
4790 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004791
Radek Krejci010e54b2016-03-15 09:40:34 +01004792 LOGVRB("Resolving unresolved data nodes and their constraints.");
4793 ly_vlog_hide(1);
4794
Radek Krejci0b7704f2016-03-18 12:16:14 +01004795 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01004796 ly_errno = LY_SUCCESS;
4797 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004798 do {
4799 progress = 0;
4800 for(i = 0; i < unres->count; i++) {
4801 if (unres->type[i] != UNRES_WHEN) {
4802 continue;
4803 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004804 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004805 /* count when-stmt nodes in unres list */
4806 when_stmt++;
4807 }
4808
4809 /* resolve when condition only when all parent when conditions are already resolved */
4810 for (parent = unres->node[i]->parent;
4811 parent && LYD_WHEN_DONE(parent->when_status);
4812 parent = parent->parent) {
4813 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
4814 /* the parent node was already unlinked, do not resolve this node,
4815 * it will be removed anyway, so just mark it as resolved
4816 */
4817 unres->node[i]->when_status |= LYD_WHEN_FALSE;
4818 unres->type[i] = UNRES_RESOLVED;
4819 resolved++;
4820 break;
4821 }
4822 }
4823 if (parent) {
4824 continue;
4825 }
Radek Krejci010e54b2016-03-15 09:40:34 +01004826
Radek Krejci48464ed2016-03-17 15:44:09 +01004827 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004828 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004829 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
4830 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01004831 /* false when condition */
4832 ly_vlog_hide(0);
4833 path = strdup(ly_errpath());
4834 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
4835 path[0] ? path : "", path[0] ? ")" : "");
4836 free(path);
4837 free(msg);
4838 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004839 } /* follows else */
4840
Radek Krejci0c0086a2016-03-24 15:20:28 +01004841 /* only unlink now, the subtree can contain another nodes stored in the unres list */
4842 /* if it has parent non-presence containers that would be empty, we should actually
4843 * remove the container
4844 */
4845 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
4846 for (parent = unres->node[i];
4847 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
4848 parent = parent->parent) {
4849 if (((struct lys_node_container *)parent->parent->schema)->presence) {
4850 /* presence container */
4851 break;
4852 }
4853 if (parent->next || parent->prev != parent) {
4854 /* non empty (the child we are in and we are going to remove is not the only child) */
4855 break;
4856 }
4857 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004858 unres->node[i] = parent;
4859 }
4860
Radek Krejci0b7704f2016-03-18 12:16:14 +01004861 /* auto-delete */
4862 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
4863 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01004864 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004865 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01004866 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004867
Radek Krejci0b7704f2016-03-18 12:16:14 +01004868 lyd_unlink(unres->node[i]);
4869 unres->type[i] = UNRES_DELETE;
4870 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01004871
4872 /* update the rest of unres items */
4873 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01004874 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01004875 continue;
4876 }
4877
4878 /* test if the node is in subtree to be deleted */
4879 for (parent = unres->node[j]; parent; parent = parent->parent) {
4880 if (parent == unres->node[i]) {
4881 /* yes, it is */
4882 unres->type[j] = UNRES_RESOLVED;
4883 resolved++;
4884 break;
4885 }
4886 }
4887 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004888 } else {
4889 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01004890 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004891 ly_errno = LY_SUCCESS;
4892 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004893 resolved++;
4894 progress = 1;
4895 } else if (rc == -1) {
4896 ly_vlog_hide(0);
4897 return -1;
4898 }
4899 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004900 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01004901 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01004902
Radek Krejci0b7704f2016-03-18 12:16:14 +01004903 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01004904 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01004905 ly_vlog_hide(0);
4906 path = strdup(ly_errpath());
4907 LOGERR(LY_EVALID, "%s%s%s%s", msg = strdup(ly_errmsg()), path[0] ? " (path: " : "",
4908 path[0] ? path : "", path[0] ? ")" : "");
4909 free(path);
4910 free(msg);
4911 return -1;
4912 }
4913
4914 for (i = 0; del_items && i < unres->count; i++) {
4915 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
4916 if (unres->type[i] != UNRES_DELETE) {
4917 continue;
4918 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01004919 if (!unres->node[i]) {
4920 unres->type[i] = UNRES_RESOLVED;
4921 del_items--;
4922 continue;
4923 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01004924
Radek Krejci0b7704f2016-03-18 12:16:14 +01004925 /* really remove the complete subtree */
4926 lyd_free(unres->node[i]);
4927 unres->type[i] = UNRES_RESOLVED;
4928 del_items--;
4929 }
Radek Krejci010e54b2016-03-15 09:40:34 +01004930
4931 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004932 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004933 if (unres->type[i] == UNRES_RESOLVED) {
4934 continue;
4935 }
4936
Radek Krejci48464ed2016-03-17 15:44:09 +01004937 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004938 if (rc == 0) {
4939 unres->type[i] = UNRES_RESOLVED;
4940 resolved++;
4941 } else if (rc == -1) {
4942 ly_vlog_hide(0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004943 return -1;
4944 }
4945 }
4946
Radek Krejci010e54b2016-03-15 09:40:34 +01004947 ly_vlog_hide(0);
4948 if (resolved < unres->count) {
4949 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
4950 * all the validation errors
4951 */
4952 for (i = 0; i < unres->count; ++i) {
4953 if (unres->type[i] == UNRES_RESOLVED) {
4954 continue;
4955 }
Radek Krejci48464ed2016-03-17 15:44:09 +01004956 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01004957 }
4958 return -1;
4959 }
4960
4961 LOGVRB("All data nodes and constraints resolved");
4962 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963 return EXIT_SUCCESS;
4964}