blob: d05e9eb28bf718d85a978a68a92346994447400e [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
32
Michal Vasko730dfdf2015-08-11 14:48:05 +020033/**
Radek Krejci6dc53a22015-08-17 13:27:59 +020034 * @brief Parse an identifier.
35 *
36 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
37 * identifier = (ALPHA / "_")
38 * *(ALPHA / DIGIT / "_" / "-" / ".")
39 *
Michal Vaskobb211122015-08-19 14:03:11 +020040 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +020041 *
42 * @return Number of characters successfully parsed.
43 */
Michal Vasko249e6b52015-08-19 11:08:52 +020044int
Radek Krejci6dc53a22015-08-17 13:27:59 +020045parse_identifier(const char *id)
46{
47 int parsed = 0;
48
Michal Vasko1ab90bc2016-03-15 10:40:22 +010049 assert(id);
50
Radek Krejci6dc53a22015-08-17 13:27:59 +020051 if (((id[0] == 'x') || (id[0] == 'X'))
Michal Vasko1ab90bc2016-03-15 10:40:22 +010052 && (id[0] && ((id[1] == 'm') || (id[0] == 'M')))
53 && (id[1] && ((id[2] == 'l') || (id[2] == 'L')))) {
Radek Krejci6dc53a22015-08-17 13:27:59 +020054 return -parsed;
55 }
56
57 if (!isalpha(id[0]) && (id[0] != '_')) {
58 return -parsed;
59 }
60
61 ++parsed;
62 ++id;
63
64 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
65 ++parsed;
66 ++id;
67 }
68
69 return parsed;
70}
71
72/**
73 * @brief Parse a node-identifier.
74 *
Michal Vasko723e50c2015-10-20 15:20:29 +020075 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +020076 *
Michal Vaskobb211122015-08-19 14:03:11 +020077 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +020078 * @param[out] mod_name Points to the module name, NULL if there is not any.
79 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +020080 * @param[out] name Points to the node name.
81 * @param[out] nam_len Length of the node name.
82 *
83 * @return Number of characters successfully parsed,
84 * positive on success, negative on failure.
85 */
86static int
Michal Vasko723e50c2015-10-20 15:20:29 +020087parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +020088{
89 int parsed = 0, ret;
90
91 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +020092 if (mod_name) {
93 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +020094 }
Michal Vasko723e50c2015-10-20 15:20:29 +020095 if (mod_name_len) {
96 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +020097 }
98 if (name) {
99 *name = NULL;
100 }
101 if (nam_len) {
102 *nam_len = 0;
103 }
104
105 if ((ret = parse_identifier(id)) < 1) {
106 return ret;
107 }
108
Michal Vasko723e50c2015-10-20 15:20:29 +0200109 if (mod_name) {
110 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200111 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200112 if (mod_name_len) {
113 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200114 }
115
116 parsed += ret;
117 id += ret;
118
119 /* there is prefix */
120 if (id[0] == ':') {
121 ++parsed;
122 ++id;
123
124 /* there isn't */
125 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200126 if (name && mod_name) {
127 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200128 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200129 if (mod_name) {
130 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200131 }
132
Michal Vasko723e50c2015-10-20 15:20:29 +0200133 if (nam_len && mod_name_len) {
134 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200135 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 if (mod_name_len) {
137 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200138 }
139
140 return parsed;
141 }
142
143 /* identifier (node name) */
144 if ((ret = parse_identifier(id)) < 1) {
145 return -parsed+ret;
146 }
147
148 if (name) {
149 *name = id;
150 }
151 if (nam_len) {
152 *nam_len = ret;
153 }
154
155 return parsed+ret;
156}
157
158/**
159 * @brief Parse a path-predicate (leafref).
160 *
161 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
162 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
163 *
Michal Vaskobb211122015-08-19 14:03:11 +0200164 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200165 * @param[out] prefix Points to the prefix, NULL if there is not any.
166 * @param[out] pref_len Length of the prefix, 0 if there is not any.
167 * @param[out] name Points to the node name.
168 * @param[out] nam_len Length of the node name.
169 * @param[out] path_key_expr Points to the path-key-expr.
170 * @param[out] pke_len Length of the path-key-expr.
171 * @param[out] has_predicate Flag to mark whether there is another predicate following.
172 *
173 * @return Number of characters successfully parsed,
174 * positive on success, negative on failure.
175 */
176static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200177parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
178 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200179{
180 const char *ptr;
181 int parsed = 0, ret;
182
183 assert(id);
184 if (prefix) {
185 *prefix = NULL;
186 }
187 if (pref_len) {
188 *pref_len = 0;
189 }
190 if (name) {
191 *name = NULL;
192 }
193 if (nam_len) {
194 *nam_len = 0;
195 }
196 if (path_key_expr) {
197 *path_key_expr = NULL;
198 }
199 if (pke_len) {
200 *pke_len = 0;
201 }
202 if (has_predicate) {
203 *has_predicate = 0;
204 }
205
206 if (id[0] != '[') {
207 return -parsed;
208 }
209
210 ++parsed;
211 ++id;
212
213 while (isspace(id[0])) {
214 ++parsed;
215 ++id;
216 }
217
218 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
219 return -parsed+ret;
220 }
221
222 parsed += ret;
223 id += ret;
224
225 while (isspace(id[0])) {
226 ++parsed;
227 ++id;
228 }
229
230 if (id[0] != '=') {
231 return -parsed;
232 }
233
234 ++parsed;
235 ++id;
236
237 while (isspace(id[0])) {
238 ++parsed;
239 ++id;
240 }
241
242 if ((ptr = strchr(id, ']')) == NULL) {
243 return -parsed;
244 }
245
246 --ptr;
247 while (isspace(ptr[0])) {
248 --ptr;
249 }
250 ++ptr;
251
252 ret = ptr-id;
253 if (path_key_expr) {
254 *path_key_expr = id;
255 }
256 if (pke_len) {
257 *pke_len = ret;
258 }
259
260 parsed += ret;
261 id += ret;
262
263 while (isspace(id[0])) {
264 ++parsed;
265 ++id;
266 }
267
268 assert(id[0] == ']');
269
270 if (id[1] == '[') {
271 *has_predicate = 1;
272 }
273
274 return parsed+1;
275}
276
277/**
278 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
279 * the ".." and the first node-identifier, other calls parse a single
280 * node-identifier each.
281 *
282 * path-key-expr = current-function-invocation *WSP "/" *WSP
283 * rel-path-keyexpr
284 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
285 * *(node-identifier *WSP "/" *WSP)
286 * node-identifier
287 *
Michal Vaskobb211122015-08-19 14:03:11 +0200288 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200289 * @param[out] prefix Points to the prefix, NULL if there is not any.
290 * @param[out] pref_len Length of the prefix, 0 if there is not any.
291 * @param[out] name Points to the node name.
292 * @param[out] nam_len Length of the node name.
293 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
294 * must not be changed between consecutive calls.
295 * @return Number of characters successfully parsed,
296 * positive on success, negative on failure.
297 */
298static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200299parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
300 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200301{
302 int parsed = 0, ret, par_times = 0;
303
304 assert(id);
305 assert(parent_times);
306 if (prefix) {
307 *prefix = NULL;
308 }
309 if (pref_len) {
310 *pref_len = 0;
311 }
312 if (name) {
313 *name = NULL;
314 }
315 if (nam_len) {
316 *nam_len = 0;
317 }
318
319 if (!*parent_times) {
320 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
321 if (strncmp(id, "current()", 9)) {
322 return -parsed;
323 }
324
325 parsed += 9;
326 id += 9;
327
328 while (isspace(id[0])) {
329 ++parsed;
330 ++id;
331 }
332
333 if (id[0] != '/') {
334 return -parsed;
335 }
336
337 ++parsed;
338 ++id;
339
340 while (isspace(id[0])) {
341 ++parsed;
342 ++id;
343 }
344
345 /* rel-path-keyexpr */
346 if (strncmp(id, "..", 2)) {
347 return -parsed;
348 }
349 ++par_times;
350
351 parsed += 2;
352 id += 2;
353
354 while (isspace(id[0])) {
355 ++parsed;
356 ++id;
357 }
358 }
359
360 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
361 *
362 * first parent reference with whitespaces already parsed
363 */
364 if (id[0] != '/') {
365 return -parsed;
366 }
367
368 ++parsed;
369 ++id;
370
371 while (isspace(id[0])) {
372 ++parsed;
373 ++id;
374 }
375
376 while (!strncmp(id, "..", 2) && !*parent_times) {
377 ++par_times;
378
379 parsed += 2;
380 id += 2;
381
382 while (isspace(id[0])) {
383 ++parsed;
384 ++id;
385 }
386
387 if (id[0] != '/') {
388 return -parsed;
389 }
390
391 ++parsed;
392 ++id;
393
394 while (isspace(id[0])) {
395 ++parsed;
396 ++id;
397 }
398 }
399
400 if (!*parent_times) {
401 *parent_times = par_times;
402 }
403
404 /* all parent references must be parsed at this point */
405 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
406 return -parsed+ret;
407 }
408
409 parsed += ret;
410 id += ret;
411
412 return parsed;
413}
414
415/**
416 * @brief Parse path-arg (leafref).
417 *
418 * path-arg = absolute-path / relative-path
419 * absolute-path = 1*("/" (node-identifier *path-predicate))
420 * relative-path = 1*(".." "/") descendant-path
421 *
Michal Vaskobb211122015-08-19 14:03:11 +0200422 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200423 * @param[out] prefix Points to the prefix, NULL if there is not any.
424 * @param[out] pref_len Length of the prefix, 0 if there is not any.
425 * @param[out] name Points to the node name.
426 * @param[out] nam_len Length of the node name.
427 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
428 * must not be changed between consecutive calls. -1 if the
429 * path is relative.
430 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
431 *
432 * @return Number of characters successfully parsed,
433 * positive on success, negative on failure.
434 */
435static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200436parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
437 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200438{
439 int parsed = 0, ret, par_times = 0;
440
441 assert(id);
442 assert(parent_times);
443 if (prefix) {
444 *prefix = NULL;
445 }
446 if (pref_len) {
447 *pref_len = 0;
448 }
449 if (name) {
450 *name = NULL;
451 }
452 if (nam_len) {
453 *nam_len = 0;
454 }
455 if (has_predicate) {
456 *has_predicate = 0;
457 }
458
459 if (!*parent_times && !strncmp(id, "..", 2)) {
460 ++par_times;
461
462 parsed += 2;
463 id += 2;
464
465 while (!strncmp(id, "/..", 3)) {
466 ++par_times;
467
468 parsed += 3;
469 id += 3;
470 }
471 }
472
473 if (!*parent_times) {
474 if (par_times) {
475 *parent_times = par_times;
476 } else {
477 *parent_times = -1;
478 }
479 }
480
481 if (id[0] != '/') {
482 return -parsed;
483 }
484
485 /* skip '/' */
486 ++parsed;
487 ++id;
488
489 /* node-identifier ([prefix:]identifier) */
490 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
491 return -parsed-ret;
492 }
493
494 parsed += ret;
495 id += ret;
496
497 /* there is no predicate */
498 if ((id[0] == '/') || !id[0]) {
499 return parsed;
500 } else if (id[0] != '[') {
501 return -parsed;
502 }
503
504 if (has_predicate) {
505 *has_predicate = 1;
506 }
507
508 return parsed;
509}
510
511/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200512 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200513 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200514 *
515 * instance-identifier = 1*("/" (node-identifier *predicate))
516 *
Michal Vaskobb211122015-08-19 14:03:11 +0200517 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200518 * @param[out] model Points to the model name.
519 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200520 * @param[out] name Points to the node name.
521 * @param[out] nam_len Length of the node name.
522 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
523 *
524 * @return Number of characters successfully parsed,
525 * positive on success, negative on failure.
526 */
527static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200528parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
529 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200530{
531 int parsed = 0, ret;
532
533 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200534 if (model) {
535 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200536 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200537 if (mod_len) {
538 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200539 }
540 if (name) {
541 *name = NULL;
542 }
543 if (nam_len) {
544 *nam_len = 0;
545 }
546 if (has_predicate) {
547 *has_predicate = 0;
548 }
549
550 if (id[0] != '/') {
551 return -parsed;
552 }
553
554 ++parsed;
555 ++id;
556
Michal Vasko1f2cc332015-08-19 11:18:32 +0200557 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Michal Vaskobea08e92016-05-18 13:28:08 +0200558 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200559 }
560
561 parsed += ret;
562 id += ret;
563
564 if ((id[0] == '[') && has_predicate) {
565 *has_predicate = 1;
566 }
567
568 return parsed;
569}
570
571/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200572 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200573 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200574 *
575 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
576 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
577 * ((DQUOTE string DQUOTE) /
578 * (SQUOTE string SQUOTE))
579 * pos = non-negative-integer-value
580 *
Michal Vaskobb211122015-08-19 14:03:11 +0200581 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200582 * @param[out] model Points to the model name.
583 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200584 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
585 * @param[out] nam_len Length of the node name.
586 * @param[out] value Value the node-identifier must have (string from the grammar),
587 * NULL if there is not any.
588 * @param[out] val_len Length of the value, 0 if there is not any.
589 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
590 *
591 * @return Number of characters successfully parsed,
592 * positive on success, negative on failure.
593 */
594static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200595parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
596 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597{
598 const char *ptr;
599 int parsed = 0, ret;
600 char quote;
601
602 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200603 if (model) {
604 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200605 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200606 if (mod_len) {
607 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200608 }
609 if (name) {
610 *name = NULL;
611 }
612 if (nam_len) {
613 *nam_len = 0;
614 }
615 if (value) {
616 *value = NULL;
617 }
618 if (val_len) {
619 *val_len = 0;
620 }
621 if (has_predicate) {
622 *has_predicate = 0;
623 }
624
625 if (id[0] != '[') {
626 return -parsed;
627 }
628
629 ++parsed;
630 ++id;
631
632 while (isspace(id[0])) {
633 ++parsed;
634 ++id;
635 }
636
637 /* pos */
638 if (isdigit(id[0])) {
639 if (name) {
640 *name = id;
641 }
642
643 if (id[0] == '0') {
644 ++parsed;
645 ++id;
646
647 if (isdigit(id[0])) {
648 return -parsed;
649 }
650 }
651
652 while (isdigit(id[0])) {
653 ++parsed;
654 ++id;
655 }
656
657 if (nam_len) {
658 *nam_len = id-(*name);
659 }
660
661 /* "." */
662 } else if (id[0] == '.') {
663 if (name) {
664 *name = id;
665 }
666 if (nam_len) {
667 *nam_len = 1;
668 }
669
670 ++parsed;
671 ++id;
672
673 /* node-identifier */
674 } else {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200675 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 return -parsed+ret;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200677 } else if (model && !*model) {
678 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200679 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200680
681 parsed += ret;
682 id += ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 }
684
685 while (isspace(id[0])) {
686 ++parsed;
687 ++id;
688 }
689
690 if (id[0] != '=') {
691 return -parsed;
692 }
693
694 ++parsed;
695 ++id;
696
697 while (isspace(id[0])) {
698 ++parsed;
699 ++id;
700 }
701
702 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
703 if ((id[0] == '\"') || (id[0] == '\'')) {
704 quote = id[0];
705
706 ++parsed;
707 ++id;
708
709 if ((ptr = strchr(id, quote)) == NULL) {
710 return -parsed;
711 }
712 ret = ptr-id;
713
714 if (value) {
715 *value = id;
716 }
717 if (val_len) {
718 *val_len = ret;
719 }
720
721 parsed += ret+1;
722 id += ret+1;
723 } else {
724 return -parsed;
725 }
726
727 while (isspace(id[0])) {
728 ++parsed;
729 ++id;
730 }
731
732 if (id[0] != ']') {
733 return -parsed;
734 }
735
736 ++parsed;
737 ++id;
738
739 if ((id[0] == '[') && has_predicate) {
740 *has_predicate = 1;
741 }
742
743 return parsed;
744}
745
746/**
747 * @brief Parse schema-nodeid.
748 *
749 * schema-nodeid = absolute-schema-nodeid /
750 * descendant-schema-nodeid
751 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200752 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200753 * node-identifier
754 * absolute-schema-nodeid
755 *
Michal Vaskobb211122015-08-19 14:03:11 +0200756 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200757 * @param[out] mod_name Points to the module name, NULL if there is not any.
758 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200759 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200760 * @param[out] nam_len Length of the node name.
761 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
762 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100763 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
764 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200765 *
766 * @return Number of characters successfully parsed,
767 * positive on success, negative on failure.
768 */
Michal Vasko22448d32016-03-16 13:17:29 +0100769int
Michal Vasko723e50c2015-10-20 15:20:29 +0200770parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100771 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200772{
773 int parsed = 0, ret;
774
775 assert(id);
776 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200777 if (mod_name) {
778 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200779 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200780 if (mod_name_len) {
781 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
783 if (name) {
784 *name = NULL;
785 }
786 if (nam_len) {
787 *nam_len = 0;
788 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100789 if (has_predicate) {
790 *has_predicate = 0;
791 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200792
793 if (id[0] != '/') {
794 if (*is_relative != -1) {
795 return -parsed;
796 } else {
797 *is_relative = 1;
798 }
Michal Vasko48935352016-03-29 11:52:36 +0200799 if (!strncmp(id, "./", 2)) {
800 parsed += 2;
801 id += 2;
802 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200803 } else {
804 if (*is_relative == -1) {
805 *is_relative = 0;
806 }
807 ++parsed;
808 ++id;
809 }
810
Michal Vasko723e50c2015-10-20 15:20:29 +0200811 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200812 return -parsed+ret;
813 }
814
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100815 parsed += ret;
816 id += ret;
817
818 if ((id[0] == '[') && has_predicate) {
819 *has_predicate = 1;
820 }
821
822 return parsed;
823}
824
825/**
826 * @brief Parse schema predicate (special format internally used).
827 *
828 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200829 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100830 * key-with-value = identifier *WSP "=" *WSP
831 * ((DQUOTE string DQUOTE) /
832 * (SQUOTE string SQUOTE))
833 *
834 * @param[in] id Identifier to use.
835 * @param[out] name Points to the list key name.
836 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100837 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100838 * @param[out] val_len Length of \p value.
839 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
840 */
Michal Vasko22448d32016-03-16 13:17:29 +0100841int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200842parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100843 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100844{
845 const char *ptr;
846 int parsed = 0, ret;
847 char quote;
848
849 assert(id);
850 if (name) {
851 *name = NULL;
852 }
853 if (nam_len) {
854 *nam_len = 0;
855 }
856 if (value) {
857 *value = NULL;
858 }
859 if (val_len) {
860 *val_len = 0;
861 }
862 if (has_predicate) {
863 *has_predicate = 0;
864 }
865
866 if (id[0] != '[') {
867 return -parsed;
868 }
869
870 ++parsed;
871 ++id;
872
873 while (isspace(id[0])) {
874 ++parsed;
875 ++id;
876 }
877
Michal Vasko22448d32016-03-16 13:17:29 +0100878 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200879 if (id[0] == '.') {
880 ret = 1;
881 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100882 return -parsed + ret;
883 }
884 if (name) {
885 *name = id;
886 }
887 if (nam_len) {
888 *nam_len = ret;
889 }
890
891 parsed += ret;
892 id += ret;
893
894 while (isspace(id[0])) {
895 ++parsed;
896 ++id;
897 }
898
899 /* there is value as well */
900 if (id[0] == '=') {
901 ++parsed;
902 ++id;
903
904 while (isspace(id[0])) {
905 ++parsed;
906 ++id;
907 }
908
909 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
910 if ((id[0] == '\"') || (id[0] == '\'')) {
911 quote = id[0];
912
913 ++parsed;
914 ++id;
915
916 if ((ptr = strchr(id, quote)) == NULL) {
917 return -parsed;
918 }
919 ret = ptr - id;
920
921 if (value) {
922 *value = id;
923 }
924 if (val_len) {
925 *val_len = ret;
926 }
927
928 parsed += ret + 1;
929 id += ret + 1;
930 } else {
931 return -parsed;
932 }
933
934 while (isspace(id[0])) {
935 ++parsed;
936 ++id;
937 }
Michal Vasko22448d32016-03-16 13:17:29 +0100938 } else if (value) {
939 /* if value was expected, it's mandatory */
940 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100941 }
942
943 if (id[0] != ']') {
944 return -parsed;
945 }
946
947 ++parsed;
948 ++id;
949
950 if ((id[0] == '[') && has_predicate) {
951 *has_predicate = 1;
952 }
953
954 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200955}
956
957/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200958 * @brief Resolve (find) a feature definition. Logs directly.
959 *
960 * @param[in] feat_name Feature name to resolve.
961 * @param[in] len Length of \p feat_name.
962 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +0200963 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
964 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200965 *
Radek Krejci9ff0a922016-07-14 13:08:05 +0200966 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200967 */
968static int
Radek Krejci9ff0a922016-07-14 13:08:05 +0200969resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200970{
971 char *str;
972 const char *mod_name, *name;
973 int mod_name_len, nam_len, i, j;
974 const struct lys_module *module;
975
Radek Krejci9ff0a922016-07-14 13:08:05 +0200976 assert(feature);
977
Michal Vaskoc5c26b02016-06-29 11:10:29 +0200978 /* check prefix */
979 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
980 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
981 return -1;
982 }
983
984 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
985 if (!module) {
986 /* identity refers unknown data model */
987 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
988 return -1;
989 }
990
Radek Krejci9ff0a922016-07-14 13:08:05 +0200991 if (module != node->module && module == lys_node_module(node)) {
992 /* first, try to search directly in submodule where the feature was mentioned */
993 for (j = 0; j < node->module->features_size; j++) {
994 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
995 /* check status */
996 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +0200997 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +0200998 return -1;
999 }
1000 *feature = &node->module->features[j];
1001 return 0;
1002 }
1003 }
1004 }
1005
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001006 /* search in the identified module ... */
1007 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001008 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001009 /* check status */
1010 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001011 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001012 return -1;
1013 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001014 *feature = &module->features[j];
1015 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001016 }
1017 }
1018 /* ... and all its submodules */
1019 for (i = 0; i < module->inc_size; i++) {
1020 if (!module->inc[i].submodule) {
1021 /* not yet resolved */
1022 continue;
1023 }
1024 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001025 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1026 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001027 /* check status */
1028 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1029 module->inc[i].submodule->features[j].flags,
1030 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001031 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001032 return -1;
1033 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001034 *feature = &module->inc[i].submodule->features[j];
1035 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001036 }
1037 }
1038 }
1039
1040 /* not found */
1041 str = strndup(feat_name, len);
1042 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1043 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001044 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001045}
1046
Radek Krejci9ff0a922016-07-14 13:08:05 +02001047/*
1048 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001049 * - 1 if enabled
1050 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001051 * - -1 if not usable by its if-feature expression
1052 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001053static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001054resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001055{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001056 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001057
Radek Krejci9ff0a922016-07-14 13:08:05 +02001058 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001059 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001060 return -1;
1061 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001062 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001063
Radek Krejci69b8d922016-07-27 13:13:41 +02001064 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001065}
1066
1067static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001068resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001069{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001070 uint8_t op;
1071 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001072
Radek Krejci9ff0a922016-07-14 13:08:05 +02001073 op = iff_getop(expr->expr, *index_e);
1074 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001075
Radek Krejci9ff0a922016-07-14 13:08:05 +02001076 switch (op) {
1077 case LYS_IFF_F:
1078 /* resolve feature */
1079 return resolve_feature_value(expr->features[(*index_f)++]);
1080 case LYS_IFF_NOT:
1081 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1082 if (rc == -1) {
1083 /* one of the referenced feature is hidden by its if-feature,
1084 * so this if-feature expression is always false */
1085 return -1;
1086 } else {
1087 /* invert result */
1088 return rc ? 0 : 1;
1089 }
1090 case LYS_IFF_AND:
1091 case LYS_IFF_OR:
1092 a = resolve_iffeature_recursive(expr, index_e, index_f);
1093 b = resolve_iffeature_recursive(expr, index_e, index_f);
1094 if (a == -1 || b == -1) {
1095 /* one of the referenced feature is hidden by its if-feature,
1096 * so this if-feature expression is always false */
1097 return -1;
1098 } else if (op == LYS_IFF_AND) {
1099 return a && b;
1100 } else { /* LYS_IFF_OR */
1101 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001102 }
1103 }
1104
Radek Krejci9ff0a922016-07-14 13:08:05 +02001105 return -1;
1106}
1107
1108int
1109resolve_iffeature(struct lys_iffeature *expr)
1110{
1111 int rc = -1;
1112 int index_e = 0, index_f = 0;
1113
1114 if (expr->expr) {
1115 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1116 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001117 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001118}
1119
1120struct iff_stack {
1121 int size;
1122 int index; /* first empty item */
1123 uint8_t *stack;
1124};
1125
1126static int
1127iff_stack_push(struct iff_stack *stack, uint8_t value)
1128{
1129 if (stack->index == stack->size) {
1130 stack->size += 4;
1131 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1132 if (!stack->stack) {
1133 LOGMEM;
1134 stack->size = 0;
1135 return EXIT_FAILURE;
1136 }
1137 }
1138
1139 stack->stack[stack->index++] = value;
1140 return EXIT_SUCCESS;
1141}
1142
1143static uint8_t
1144iff_stack_pop(struct iff_stack *stack)
1145{
1146 stack->index--;
1147 return stack->stack[stack->index];
1148}
1149
1150static void
1151iff_stack_clean(struct iff_stack *stack)
1152{
1153 stack->size = 0;
1154 free(stack->stack);
1155}
1156
1157static void
1158iff_setop(uint8_t *list, uint8_t op, int pos)
1159{
1160 uint8_t *item;
1161 uint8_t mask = 3;
1162
1163 assert(pos >= 0);
1164 assert(op <= 3); /* max 2 bits */
1165
1166 item = &list[pos / 4];
1167 mask = mask << 2 * (pos % 4);
1168 *item = (*item) & ~mask;
1169 *item = (*item) | (op << 2 * (pos % 4));
1170}
1171
1172uint8_t
1173iff_getop(uint8_t *list, int pos)
1174{
1175 uint8_t *item;
1176 uint8_t mask = 3, result;
1177
1178 assert(pos >= 0);
1179
1180 item = &list[pos / 4];
1181 result = (*item) & (mask << 2 * (pos % 4));
1182 return result >> 2 * (pos % 4);
1183}
1184
1185#define LYS_IFF_LP 0x04 /* ( */
1186#define LYS_IFF_RP 0x08 /* ) */
1187
1188void
1189resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1190{
1191 unsigned int e = 0, f = 0, r = 0;
1192 uint8_t op;
1193
1194 assert(iffeat);
1195
1196 if (!iffeat->expr) {
1197 goto result;
1198 }
1199
1200 do {
1201 op = iff_getop(iffeat->expr, e++);
1202 switch (op) {
1203 case LYS_IFF_NOT:
1204 if (!r) {
1205 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001206 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001207 break;
1208 case LYS_IFF_AND:
1209 case LYS_IFF_OR:
1210 if (!r) {
1211 r += 2;
1212 } else {
1213 r += 1;
1214 }
1215 break;
1216 case LYS_IFF_F:
1217 f++;
1218 if (r) {
1219 r--;
1220 }
1221 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001222 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001223 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001224
Radek Krejci9ff0a922016-07-14 13:08:05 +02001225result:
1226 if (expr_size) {
1227 *expr_size = e;
1228 }
1229 if (feat_size) {
1230 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001231 }
1232}
1233
1234int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001235resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1236 struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001237{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001238 const char *c = value;
1239 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001240 int i, j, last_not, checkversion = 0;
1241 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001242 uint8_t op;
1243 struct iff_stack stack = {0, 0, NULL};
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001244
Radek Krejci9ff0a922016-07-14 13:08:05 +02001245 assert(c);
1246
1247 if (isspace(c[0])) {
1248 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1249 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001250 }
1251
Radek Krejci9ff0a922016-07-14 13:08:05 +02001252 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1253 for (i = j = last_not = 0; c[i]; i++) {
1254 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001255 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001256 j++;
1257 continue;
1258 } else if (c[i] == ')') {
1259 j--;
1260 continue;
1261 } else if (isspace(c[i])) {
1262 continue;
1263 }
1264
1265 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1266 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001267 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001268 return EXIT_FAILURE;
1269 } else if (!isspace(c[i + r])) {
1270 /* feature name starting with the not/and/or */
1271 last_not = 0;
1272 f_size++;
1273 } else if (c[i] == 'n') { /* not operation */
1274 if (last_not) {
1275 /* double not */
1276 expr_size = expr_size - 2;
1277 last_not = 0;
1278 } else {
1279 last_not = 1;
1280 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001281 } else { /* and, or */
1282 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001283 /* not a not operation */
1284 last_not = 0;
1285 }
1286 i += r;
1287 } else {
1288 f_size++;
1289 last_not = 0;
1290 }
1291 expr_size++;
1292
1293 while (!isspace(c[i])) {
1294 if (!c[i] || c[i] == ')') {
1295 i--;
1296 break;
1297 }
1298 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001299 }
1300 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001301 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001302 /* not matching count of ( and ) */
1303 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1304 return EXIT_FAILURE;
1305 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001306
Radek Krejci69b8d922016-07-27 13:13:41 +02001307 if (checkversion || expr_size > 1) {
1308 /* check that we have 1.1 module */
1309 if (node->module->version != 2) {
1310 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1311 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1312 return EXIT_FAILURE;
1313 }
1314 }
1315
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 /* allocate the memory */
1317 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
1318 iffeat_expr->features = malloc(f_size * sizeof *iffeat_expr->features);
1319 stack.size = expr_size;
1320 stack.stack = malloc(expr_size * sizeof *stack.stack);
1321 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1322 LOGMEM;
1323 goto error;
1324 }
1325 f_size--; expr_size--; /* used as indexes from now */
1326
1327 for (i--; i >= 0; i--) {
1328 if (c[i] == ')') {
1329 /* push it on stack */
1330 iff_stack_push(&stack, LYS_IFF_RP);
1331 continue;
1332 } else if (c[i] == '(') {
1333 /* pop from the stack into result all operators until ) */
1334 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1335 iff_setop(iffeat_expr->expr, op, expr_size--);
1336 }
1337 continue;
1338 } else if (isspace(c[i])) {
1339 continue;
1340 }
1341
1342 /* end operator or operand -> find beginning and get what is it */
1343 j = i + 1;
1344 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1345 i--;
1346 }
1347 i++; /* get back by one step */
1348
1349 if (!strncmp(&c[i], "not ", 4)) {
1350 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1351 /* double not */
1352 iff_stack_pop(&stack);
1353 } else {
1354 /* not has the highest priority, so do not pop from the stack
1355 * as in case of AND and OR */
1356 iff_stack_push(&stack, LYS_IFF_NOT);
1357 }
1358 } else if (!strncmp(&c[i], "and ", 4)) {
1359 /* as for OR - pop from the stack all operators with the same or higher
1360 * priority and store them to the result, then push the AND to the stack */
1361 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1362 op = iff_stack_pop(&stack);
1363 iff_setop(iffeat_expr->expr, op, expr_size--);
1364 }
1365 iff_stack_push(&stack, LYS_IFF_AND);
1366 } else if (!strncmp(&c[i], "or ", 3)) {
1367 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1368 op = iff_stack_pop(&stack);
1369 iff_setop(iffeat_expr->expr, op, expr_size--);
1370 }
1371 iff_stack_push(&stack, LYS_IFF_OR);
1372 } else {
1373 /* feature name, length is j - i */
1374
1375 /* add it to the result */
1376 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1377
1378 /* now get the link to the feature definition. Since it can be
1379 * forward referenced, we have hack for unres - until resolved,
1380 * the feature name is stored instead of link to the lys_feature */
1381 iffeat_expr->features[f_size] = (void*)strndup(&c[i], j - i);
1382 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT, node);
1383 f_size--;
1384
1385 if (r == -1) {
1386 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001387 }
1388 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001389 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 while (stack.index) {
1391 op = iff_stack_pop(&stack);
1392 iff_setop(iffeat_expr->expr, op, expr_size--);
1393 }
1394
1395 if (++expr_size || ++f_size) {
1396 /* not all expected operators and operands found */
1397 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1398 rc = EXIT_FAILURE;
1399 } else {
1400 rc = EXIT_SUCCESS;
1401 }
1402
1403error:
1404 /* cleanup */
1405 iff_stack_clean(&stack);
1406
1407 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001408}
1409
1410/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001411 * @brief Resolve (find) a data node based on a schema-nodeid.
1412 *
1413 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1414 * module).
1415 *
1416 */
1417struct lyd_node *
1418resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1419{
1420 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001421 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001422 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001423 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001424
1425 assert(nodeid && start);
1426
1427 if (nodeid[0] == '/') {
1428 return NULL;
1429 }
1430
1431 str = p = strdup(nodeid);
1432 if (!str) {
1433 LOGMEM;
1434 return NULL;
1435 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001436
Michal Vasko3edeaf72016-02-11 13:17:43 +01001437 while (p) {
1438 token = p;
1439 p = strchr(p, '/');
1440 if (p) {
1441 *p = '\0';
1442 p++;
1443 }
1444
Radek Krejci5da4eb62016-04-08 14:45:51 +02001445 if (p) {
1446 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001447 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001448 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001449 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001450 result = NULL;
1451 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001452 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001453
Radek Krejci5da4eb62016-04-08 14:45:51 +02001454 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1455 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001456 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001457 /* shorthand case */
1458 if (!shorthand) {
1459 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001460 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001461 continue;
1462 } else {
1463 shorthand = 0;
1464 if (schema->nodetype == LYS_LEAF) {
1465 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1466 result = NULL;
1467 break;
1468 }
1469 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001470 }
1471 } else {
1472 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001473 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1474 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001475 || !schema) {
1476 result = NULL;
1477 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001478 }
1479 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001480 LY_TREE_FOR(result ? result->child : start, iter) {
1481 if (iter->schema == schema) {
1482 /* move in data tree according to returned schema */
1483 result = iter;
1484 break;
1485 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001486 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001487 if (!iter) {
1488 /* instance not found */
1489 result = NULL;
1490 break;
1491 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001492 }
1493 free(str);
1494
1495 return result;
1496}
1497
Radek Krejcibdf92362016-04-08 14:43:34 +02001498/*
1499 * 0 - ok (done)
1500 * 1 - continue
1501 * 2 - break
1502 * -1 - error
1503 */
1504static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001505schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001506 const struct lys_module *module, const char *mod_name, int mod_name_len,
1507 const struct lys_node **start)
1508{
1509 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001510 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001511
1512 /* module check */
1513 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1514 if (!prefix_mod) {
1515 return -1;
1516 }
1517 if (prefix_mod != lys_node_module(sibling)) {
1518 return 1;
1519 }
1520
1521 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001522 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001523 if (*shorthand != -1) {
1524 *shorthand = *shorthand ? 0 : 1;
1525 }
1526 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001527 }
1528
1529 /* the result node? */
1530 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001531 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001532 return 1;
1533 }
1534 return 0;
1535 }
1536
Radek Krejcicc217a62016-04-08 16:58:11 +02001537 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001538 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001539 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001540 return -1;
1541 }
1542 *start = sibling->child;
1543 }
1544
1545 return 2;
1546}
1547
Michal Vasko3edeaf72016-02-11 13:17:43 +01001548/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1549int
1550resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1551 const struct lys_node **ret)
1552{
1553 const char *name, *mod_name, *id;
1554 const struct lys_node *sibling;
1555 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001556 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001557 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001558 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001559
1560 assert(nodeid && (start || module) && !(start && module) && ret);
1561
1562 id = nodeid;
1563
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001564 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 +01001565 return ((id - nodeid) - r) + 1;
1566 }
1567 id += r;
1568
1569 if ((is_relative && !start) || (!is_relative && !module)) {
1570 return -1;
1571 }
1572
1573 /* descendant-schema-nodeid */
1574 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001575 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001576
1577 /* absolute-schema-nodeid */
1578 } else {
1579 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001580 if (!start_mod) {
1581 return -1;
1582 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001583 start = start_mod->data;
1584 }
1585
1586 while (1) {
1587 sibling = NULL;
1588 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1589 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1590 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001591 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001592 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1593 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001594 *ret = sibling;
1595 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001596 } else if (r == 1) {
1597 continue;
1598 } else if (r == 2) {
1599 break;
1600 } else {
1601 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001602 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001603 }
1604 }
1605
1606 /* no match */
1607 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001608 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001609 return EXIT_SUCCESS;
1610 }
1611
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001612 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 +01001613 return ((id - nodeid) - r) + 1;
1614 }
1615 id += r;
1616 }
1617
1618 /* cannot get here */
1619 LOGINT;
1620 return -1;
1621}
1622
Radek Krejcif3c71de2016-04-11 12:45:46 +02001623/* unique, refine,
1624 * >0 - unexpected char on position (ret - 1),
1625 * 0 - ok (but ret can still be NULL),
1626 * -1 - error,
1627 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001628int
1629resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001630 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001631{
1632 const char *name, *mod_name, *id;
1633 const struct lys_node *sibling;
1634 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001635 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001636 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001637 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001638
1639 assert(nodeid && start && ret);
1640 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1641
1642 id = nodeid;
1643 module = start->module;
1644
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001645 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 +01001646 return ((id - nodeid) - r) + 1;
1647 }
1648 id += r;
1649
1650 if (!is_relative) {
1651 return -1;
1652 }
1653
1654 while (1) {
1655 sibling = NULL;
1656 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1657 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1658 /* name match */
1659 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001660 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1661 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001662 if (!(sibling->nodetype & ret_nodetype)) {
1663 /* wrong node type, too bad */
1664 continue;
1665 }
1666 *ret = sibling;
1667 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001668 } else if (r == 1) {
1669 continue;
1670 } else if (r == 2) {
1671 break;
1672 } else {
1673 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001674 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001675 }
1676 }
1677
1678 /* no match */
1679 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001680 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001681 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001682 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1683 *ret = NULL;
1684 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001685 }
1686
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001687 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 +01001688 return ((id - nodeid) - r) + 1;
1689 }
1690 id += r;
1691 }
1692
1693 /* cannot get here */
1694 LOGINT;
1695 return -1;
1696}
1697
1698/* choice default */
1699int
1700resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1701{
1702 /* cannot actually be a path */
1703 if (strchr(nodeid, '/')) {
1704 return -1;
1705 }
1706
Radek Krejcif3c71de2016-04-11 12:45:46 +02001707 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001708}
1709
1710/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1711static int
1712resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1713{
1714 const struct lys_module *module;
1715 const char *mod_prefix, *name;
1716 int i, mod_prefix_len, nam_len;
1717
1718 /* parse the identifier, it must be parsed on one call */
1719 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1720 return -i + 1;
1721 }
1722
1723 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1724 if (!module) {
1725 return -1;
1726 }
1727 if (module != start->module) {
1728 start = module->data;
1729 }
1730
1731 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1732
1733 return EXIT_SUCCESS;
1734}
1735
1736int
1737resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1738 const struct lys_node **ret)
1739{
1740 const char *name, *mod_name, *id;
1741 const struct lys_node *sibling, *start;
1742 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001743 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001744 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001745
1746 assert(nodeid && module && ret);
1747 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1748
1749 id = nodeid;
1750 start = module->data;
1751
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001752 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 +01001753 return ((id - nodeid) - r) + 1;
1754 }
1755 id += r;
1756
1757 if (is_relative) {
1758 return -1;
1759 }
1760
1761 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001762 if (!abs_start_mod) {
1763 return -1;
1764 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001765
1766 while (1) {
1767 sibling = NULL;
1768 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1769 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1770 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001771 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001772 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, &start);
1773 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001774 if (!(sibling->nodetype & ret_nodetype)) {
1775 /* wrong node type, too bad */
1776 continue;
1777 }
1778 *ret = sibling;
1779 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001780 } else if (r == 1) {
1781 continue;
1782 } else if (r == 2) {
1783 break;
1784 } else {
1785 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001786 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001787 }
1788 }
1789
1790 /* no match */
1791 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001792 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001793 return EXIT_SUCCESS;
1794 }
1795
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001796 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 +01001797 return ((id - nodeid) - r) + 1;
1798 }
1799 id += r;
1800 }
1801
1802 /* cannot get here */
1803 LOGINT;
1804 return -1;
1805}
1806
Michal Vaskoe733d682016-03-14 09:08:27 +01001807static int
Michal Vasko3547c532016-03-14 09:40:50 +01001808resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001809{
1810 const char *name;
1811 int nam_len, has_predicate, i;
1812
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001813 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1814 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001815 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001816 return -1;
1817 }
1818
1819 predicate += i;
1820 *parsed += i;
1821
1822 for (i = 0; i < list->keys_size; ++i) {
1823 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1824 break;
1825 }
1826 }
1827
1828 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001829 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001830 return -1;
1831 }
1832
1833 /* more predicates? */
1834 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001835 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001836 }
1837
1838 return 0;
1839}
1840
Michal Vasko9fd98e22016-04-07 15:44:19 +02001841/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly
1842 * data_nodeid - 0 schema nodeid, 1 - data nodeid with RPC input, 2 - data nodeid with RPC output */
Michal Vaskoe733d682016-03-14 09:08:27 +01001843const struct lys_node *
Michal Vaskoa9c8e992016-07-26 16:27:05 +02001844resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int data_nodeid)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001845{
Michal Vasko10728b52016-04-07 14:26:29 +02001846 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001847 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001848 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001849 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001850 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001851 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001852
Michal Vasko3547c532016-03-14 09:40:50 +01001853 assert(nodeid && (ctx || start));
1854 if (!ctx) {
1855 ctx = start->module->ctx;
1856 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001857
1858 id = nodeid;
1859
Michal Vaskoe733d682016-03-14 09:08:27 +01001860 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 +01001861 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001862 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001863 }
1864 id += r;
1865
1866 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001867 assert(start);
1868 start = start->child;
1869 if (!start) {
1870 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001871 str = strndup(nodeid, (name + nam_len) - nodeid);
1872 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1873 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001874 return NULL;
1875 }
1876 module = start->module;
1877 } else {
1878 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001879 str = strndup(nodeid, (name + nam_len) - nodeid);
1880 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1881 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001882 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001883 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1884 LOGINT;
1885 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001886 }
1887
Michal Vasko971a3ca2016-04-01 13:09:29 +02001888 if (ly_buf_used && module_name[0]) {
1889 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1890 }
1891 ly_buf_used++;
1892
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001893 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001894 module_name[mod_name_len] = '\0';
1895 module = ly_ctx_get_module(ctx, module_name, NULL);
1896
1897 if (buf_backup) {
1898 /* return previous internal buffer content */
1899 strcpy(module_name, buf_backup);
1900 free(buf_backup);
1901 buf_backup = NULL;
1902 }
1903 ly_buf_used--;
1904
Michal Vasko3547c532016-03-14 09:40:50 +01001905 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001906 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1907 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1908 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001909 return NULL;
1910 }
1911 start = module->data;
1912
1913 /* now it's as if there was no module name */
1914 mod_name = NULL;
1915 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01001916 }
1917
Michal Vaskoe733d682016-03-14 09:08:27 +01001918 prev_mod = module;
1919
Michal Vasko3edeaf72016-02-11 13:17:43 +01001920 while (1) {
1921 sibling = NULL;
Michal Vasko9fd98e22016-04-07 15:44:19 +02001922 while ((sibling = lys_getnext(sibling, lys_parent(start), module, (data_nodeid ?
1923 0 : LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT)))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001924 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001925 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001926
1927 /* data RPC input/output check */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001928 if ((data_nodeid == 1) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_OUTPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001929 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001930 } else if ((data_nodeid == 2) && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_INPUT)) {
Michal Vasko9fd98e22016-04-07 15:44:19 +02001931 continue;
1932 }
1933
Michal Vasko3edeaf72016-02-11 13:17:43 +01001934 /* module check */
1935 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02001936 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01001937 LOGINT;
1938 return NULL;
1939 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02001940
1941 if (ly_buf_used && module_name[0]) {
1942 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1943 }
1944 ly_buf_used++;
1945
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001946 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01001947 module_name[mod_name_len] = '\0';
1948 /* will also find an augment module */
1949 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001950
1951 if (buf_backup) {
1952 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02001953 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001954 free(buf_backup);
1955 buf_backup = NULL;
1956 }
1957 ly_buf_used--;
1958
Michal Vasko3edeaf72016-02-11 13:17:43 +01001959 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02001960 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1961 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1962 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01001963 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001964 }
1965 } else {
1966 prefix_mod = prev_mod;
1967 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01001968 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001969 continue;
1970 }
1971
Michal Vaskoe733d682016-03-14 09:08:27 +01001972 /* do we have some predicates on it? */
1973 if (has_predicate) {
1974 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001975 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
1976 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
1977 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
1978 return NULL;
1979 }
1980 } else if (sibling->nodetype == LYS_LIST) {
1981 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
1982 return NULL;
1983 }
1984 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01001985 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01001986 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01001987 }
1988 id += r;
1989 }
1990
Radek Krejcibdf92362016-04-08 14:43:34 +02001991 /* check for shorthand cases - then 'start' does not change */
Michal Vasko3c0f9f52016-05-17 16:38:10 +02001992 if (!data_nodeid && lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001993 shorthand = ~shorthand;
1994 }
1995
Michal Vasko3edeaf72016-02-11 13:17:43 +01001996 /* the result node? */
1997 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001998 if (shorthand) {
1999 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002000 str = strndup(nodeid, (name + nam_len) - nodeid);
2001 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002002 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002003 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002004 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002005 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002006 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002007 }
2008
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002009 if (data_nodeid || !shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002010 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002011 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002012 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002013 return NULL;
2014 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002015 start = sibling->child;
2016 }
2017
2018 /* update prev mod */
2019 prev_mod = start->module;
2020 break;
2021 }
2022 }
2023
2024 /* no match */
2025 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002026 str = strndup(nodeid, (name + nam_len) - nodeid);
2027 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2028 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002029 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002030 }
2031
Michal Vaskoe733d682016-03-14 09:08:27 +01002032 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 +01002033 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002034 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002035 }
2036 id += r;
2037 }
2038
2039 /* cannot get here */
2040 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002041 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002042}
2043
Michal Vasko22448d32016-03-16 13:17:29 +01002044static int
2045resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2046{
2047 const char *name, *value;
2048 int nam_len, val_len, has_predicate = 1, r;
2049 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002050 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002051
Radek Krejci61a86c62016-03-24 11:06:44 +01002052 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002053 assert(node->schema->nodetype == LYS_LIST);
2054
Michal Vaskof29903d2016-04-18 13:13:10 +02002055 key = (struct lyd_node_leaf_list *)node->child;
2056 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2057 if (!key) {
2058 /* invalid data */
2059 LOGINT;
2060 return -1;
2061 }
Michal Vasko22448d32016-03-16 13:17:29 +01002062
Michal Vasko22448d32016-03-16 13:17:29 +01002063 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002064 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002065 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002066 }
2067
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002068 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2069 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002070 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002071 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002072 }
2073
2074 predicate += r;
2075 *parsed += r;
2076
Michal Vaskof29903d2016-04-18 13:13:10 +02002077 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002078 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002079 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002080 }
2081
2082 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002083 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002084 return 1;
2085 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002086
2087 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002088 }
2089
2090 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002091 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002092 return -1;
2093 }
2094
2095 return 0;
2096}
2097
Radek Krejci45826012016-08-24 15:07:57 +02002098/**
2099 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2100 *
2101 * @param[in] nodeid Node data path to find
2102 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2103 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2104 * @param[out] parsed Number of characters processed in \p id
2105 * @return The closes parent (or the node itself) from the path
2106 */
Michal Vasko22448d32016-03-16 13:17:29 +01002107struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002108resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2109 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002110{
Michal Vasko10728b52016-04-07 14:26:29 +02002111 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01002112 const char *id, *mod_name, *name;
2113 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002114 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002115 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002116 const struct lys_module *prefix_mod, *prev_mod;
2117 struct ly_ctx *ctx;
2118
2119 assert(nodeid && start && parsed);
2120
2121 ctx = start->schema->module->ctx;
2122 id = nodeid;
2123
2124 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 +01002125 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002126 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002127 return NULL;
2128 }
2129 id += r;
2130 /* add it to parsed only after the data node was actually found */
2131 last_parsed = r;
2132
2133 if (is_relative) {
2134 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002135 start = start->child;
2136 } else {
2137 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002138 prev_mod = start->schema->module;
2139 }
2140
2141 while (1) {
2142 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01002143 /* RPC data check, return simply invalid argument, because the data tree is invalid */
2144 if (lys_parent(sibling->schema)) {
2145 if (options & LYD_PATH_OPT_OUTPUT) {
2146 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002147 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002148 *parsed = -1;
2149 return NULL;
2150 }
2151 } else {
2152 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002153 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002154 *parsed = -1;
2155 return NULL;
2156 }
2157 }
2158 }
2159
Michal Vasko22448d32016-03-16 13:17:29 +01002160 /* name match */
2161 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2162
2163 /* module check */
2164 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002165 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002166 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002167 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002168 return NULL;
2169 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002170
2171 if (ly_buf_used && module_name[0]) {
2172 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2173 }
2174 ly_buf_used++;
2175
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002176 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002177 module_name[mod_name_len] = '\0';
2178 /* will also find an augment module */
2179 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002180
2181 if (buf_backup) {
2182 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002183 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002184 free(buf_backup);
2185 buf_backup = NULL;
2186 }
2187 ly_buf_used--;
2188
Michal Vasko22448d32016-03-16 13:17:29 +01002189 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002190 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2191 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2192 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002193 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002194 return NULL;
2195 }
2196 } else {
2197 prefix_mod = prev_mod;
2198 }
2199 if (prefix_mod != lys_node_module(sibling->schema)) {
2200 continue;
2201 }
2202
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002203 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002204 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002205 llist = (struct lyd_node_leaf_list *)sibling;
2206 if ((!llist_value && llist->value_str && llist->value_str[0])
2207 || (llist_value && strcmp(llist_value, llist->value_str))) {
2208 continue;
2209 }
Radek Krejci45826012016-08-24 15:07:57 +02002210 } else if (sibling->schema->nodetype == LYS_LIST) {
2211 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002212 r = 0;
2213 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002214 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002215 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002216 return NULL;
2217 }
2218 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2219 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002220 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002221 return NULL;
2222 } else if (ret == 1) {
2223 /* this list instance does not match */
2224 continue;
2225 }
2226 id += r;
2227 last_parsed += r;
2228 }
2229
2230 *parsed += last_parsed;
2231
2232 /* the result node? */
2233 if (!id[0]) {
2234 return sibling;
2235 }
2236
2237 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002238 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002239 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002240 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002241 return NULL;
2242 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002243 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002244 start = sibling->child;
2245 if (start) {
2246 prev_mod = start->schema->module;
2247 }
2248 break;
2249 }
2250 }
2251
2252 /* no match, return last match */
2253 if (!sibling) {
2254 return last_match;
2255 }
2256
2257 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 +01002258 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002259 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002260 return NULL;
2261 }
2262 id += r;
2263 last_parsed = r;
2264 }
2265
2266 /* cannot get here */
2267 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002268 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002269 return NULL;
2270}
2271
Michal Vasko3edeaf72016-02-11 13:17:43 +01002272/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002273 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002274 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002275 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002276 * @param[in] str_restr Restriction as a string.
2277 * @param[in] type Type of the restriction.
2278 * @param[out] ret Final interval structure that starts with
2279 * the interval of the initial type, continues with intervals
2280 * of any superior types derived from the initial one, and
2281 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002282 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002283 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002284 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002285int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002286resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002287{
2288 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002289 int kind;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002290 int64_t local_smin, local_smax;
2291 uint64_t local_umin, local_umax;
2292 long double local_fmin, local_fmax;
2293 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002294 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002295
2296 switch (type->base) {
2297 case LY_TYPE_BINARY:
2298 kind = 0;
2299 local_umin = 0;
2300 local_umax = 18446744073709551615UL;
2301
2302 if (!str_restr && type->info.binary.length) {
2303 str_restr = type->info.binary.length->expr;
2304 }
2305 break;
2306 case LY_TYPE_DEC64:
2307 kind = 2;
Radek Krejci8c3b4b62016-06-17 14:32:12 +02002308 local_fmin = ((long double)-9223372036854775808.0) / type->info.dec64.div;
2309 local_fmax = ((long double)9223372036854775807.0) / type->info.dec64.div;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002310
2311 if (!str_restr && type->info.dec64.range) {
2312 str_restr = type->info.dec64.range->expr;
2313 }
2314 break;
2315 case LY_TYPE_INT8:
2316 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002317 local_smin = __INT64_C(-128);
2318 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002319
2320 if (!str_restr && type->info.num.range) {
2321 str_restr = type->info.num.range->expr;
2322 }
2323 break;
2324 case LY_TYPE_INT16:
2325 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002326 local_smin = __INT64_C(-32768);
2327 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002328
2329 if (!str_restr && type->info.num.range) {
2330 str_restr = type->info.num.range->expr;
2331 }
2332 break;
2333 case LY_TYPE_INT32:
2334 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002335 local_smin = __INT64_C(-2147483648);
2336 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002337
2338 if (!str_restr && type->info.num.range) {
2339 str_restr = type->info.num.range->expr;
2340 }
2341 break;
2342 case LY_TYPE_INT64:
2343 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002344 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2345 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002346
2347 if (!str_restr && type->info.num.range) {
2348 str_restr = type->info.num.range->expr;
2349 }
2350 break;
2351 case LY_TYPE_UINT8:
2352 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002353 local_umin = __UINT64_C(0);
2354 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002355
2356 if (!str_restr && type->info.num.range) {
2357 str_restr = type->info.num.range->expr;
2358 }
2359 break;
2360 case LY_TYPE_UINT16:
2361 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002362 local_umin = __UINT64_C(0);
2363 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002364
2365 if (!str_restr && type->info.num.range) {
2366 str_restr = type->info.num.range->expr;
2367 }
2368 break;
2369 case LY_TYPE_UINT32:
2370 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002371 local_umin = __UINT64_C(0);
2372 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002373
2374 if (!str_restr && type->info.num.range) {
2375 str_restr = type->info.num.range->expr;
2376 }
2377 break;
2378 case LY_TYPE_UINT64:
2379 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002380 local_umin = __UINT64_C(0);
2381 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002382
2383 if (!str_restr && type->info.num.range) {
2384 str_restr = type->info.num.range->expr;
2385 }
2386 break;
2387 case LY_TYPE_STRING:
2388 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002389 local_umin = __UINT64_C(0);
2390 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002391
2392 if (!str_restr && type->info.str.length) {
2393 str_restr = type->info.str.length->expr;
2394 }
2395 break;
2396 default:
2397 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002398 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002399 }
2400
2401 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002402 if (type->der) {
2403 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002404 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002405 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002406 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002407 assert(!intv || (intv->kind == kind));
2408 }
2409
2410 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002411 /* we do not have any restriction, return superior ones */
2412 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002413 return EXIT_SUCCESS;
2414 }
2415
2416 /* adjust local min and max */
2417 if (intv) {
2418 tmp_intv = intv;
2419
2420 if (kind == 0) {
2421 local_umin = tmp_intv->value.uval.min;
2422 } else if (kind == 1) {
2423 local_smin = tmp_intv->value.sval.min;
2424 } else if (kind == 2) {
2425 local_fmin = tmp_intv->value.fval.min;
2426 }
2427
2428 while (tmp_intv->next) {
2429 tmp_intv = tmp_intv->next;
2430 }
2431
2432 if (kind == 0) {
2433 local_umax = tmp_intv->value.uval.max;
2434 } else if (kind == 1) {
2435 local_smax = tmp_intv->value.sval.max;
2436 } else if (kind == 2) {
2437 local_fmax = tmp_intv->value.fval.max;
2438 }
2439 }
2440
2441 /* finally parse our restriction */
2442 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002443 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002444 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002445 if (!tmp_local_intv) {
2446 assert(!local_intv);
2447 local_intv = malloc(sizeof *local_intv);
2448 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002449 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002450 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002451 tmp_local_intv = tmp_local_intv->next;
2452 }
Michal Vasko253035f2015-12-17 16:58:13 +01002453 if (!tmp_local_intv) {
2454 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002455 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002456 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002457
2458 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002459 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002460 tmp_local_intv->next = NULL;
2461
2462 /* min */
2463 ptr = seg_ptr;
2464 while (isspace(ptr[0])) {
2465 ++ptr;
2466 }
2467 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2468 if (kind == 0) {
2469 tmp_local_intv->value.uval.min = atoll(ptr);
2470 } else if (kind == 1) {
2471 tmp_local_intv->value.sval.min = atoll(ptr);
2472 } else if (kind == 2) {
2473 tmp_local_intv->value.fval.min = atoll(ptr);
2474 }
2475
2476 if ((ptr[0] == '+') || (ptr[0] == '-')) {
2477 ++ptr;
2478 }
2479 while (isdigit(ptr[0])) {
2480 ++ptr;
2481 }
2482 } else if (!strncmp(ptr, "min", 3)) {
2483 if (kind == 0) {
2484 tmp_local_intv->value.uval.min = local_umin;
2485 } else if (kind == 1) {
2486 tmp_local_intv->value.sval.min = local_smin;
2487 } else if (kind == 2) {
2488 tmp_local_intv->value.fval.min = local_fmin;
2489 }
2490
2491 ptr += 3;
2492 } else if (!strncmp(ptr, "max", 3)) {
2493 if (kind == 0) {
2494 tmp_local_intv->value.uval.min = local_umax;
2495 } else if (kind == 1) {
2496 tmp_local_intv->value.sval.min = local_smax;
2497 } else if (kind == 2) {
2498 tmp_local_intv->value.fval.min = local_fmax;
2499 }
2500
2501 ptr += 3;
2502 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002503 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002504 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002505 }
2506
2507 while (isspace(ptr[0])) {
2508 ptr++;
2509 }
2510
2511 /* no interval or interval */
2512 if ((ptr[0] == '|') || !ptr[0]) {
2513 if (kind == 0) {
2514 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2515 } else if (kind == 1) {
2516 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2517 } else if (kind == 2) {
2518 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2519 }
2520 } else if (!strncmp(ptr, "..", 2)) {
2521 /* skip ".." */
2522 ptr += 2;
2523 while (isspace(ptr[0])) {
2524 ++ptr;
2525 }
2526
2527 /* max */
2528 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2529 if (kind == 0) {
2530 tmp_local_intv->value.uval.max = atoll(ptr);
2531 } else if (kind == 1) {
2532 tmp_local_intv->value.sval.max = atoll(ptr);
2533 } else if (kind == 2) {
2534 tmp_local_intv->value.fval.max = atoll(ptr);
2535 }
2536 } else if (!strncmp(ptr, "max", 3)) {
2537 if (kind == 0) {
2538 tmp_local_intv->value.uval.max = local_umax;
2539 } else if (kind == 1) {
2540 tmp_local_intv->value.sval.max = local_smax;
2541 } else if (kind == 2) {
2542 tmp_local_intv->value.fval.max = local_fmax;
2543 }
2544 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002545 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002546 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002547 }
2548 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002549 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002550 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002551 }
2552
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002553 /* check min and max in correct order*/
2554 if (kind == 0) {
2555 /* current segment */
2556 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2557 goto error;
2558 }
2559 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2560 goto error;
2561 }
2562 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002563 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002564 goto error;
2565 }
2566 } else if (kind == 1) {
2567 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2568 goto error;
2569 }
2570 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2571 goto error;
2572 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002573 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002574 goto error;
2575 }
2576 } else if (kind == 2) {
2577 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2578 goto error;
2579 }
2580 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2581 goto error;
2582 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002583 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002584 goto error;
2585 }
2586 }
2587
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002588 /* next segment (next OR) */
2589 seg_ptr = strchr(seg_ptr, '|');
2590 if (!seg_ptr) {
2591 break;
2592 }
2593 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002594 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002595 }
2596
2597 /* check local restrictions against superior ones */
2598 if (intv) {
2599 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002600 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002601
2602 while (tmp_local_intv && tmp_intv) {
2603 /* reuse local variables */
2604 if (kind == 0) {
2605 local_umin = tmp_local_intv->value.uval.min;
2606 local_umax = tmp_local_intv->value.uval.max;
2607
2608 /* it must be in this interval */
2609 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2610 /* this interval is covered, next one */
2611 if (local_umax <= tmp_intv->value.uval.max) {
2612 tmp_local_intv = tmp_local_intv->next;
2613 continue;
2614 /* ascending order of restrictions -> fail */
2615 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002616 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002617 }
2618 }
2619 } else if (kind == 1) {
2620 local_smin = tmp_local_intv->value.sval.min;
2621 local_smax = tmp_local_intv->value.sval.max;
2622
2623 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2624 if (local_smax <= tmp_intv->value.sval.max) {
2625 tmp_local_intv = tmp_local_intv->next;
2626 continue;
2627 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002628 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002629 }
2630 }
2631 } else if (kind == 2) {
2632 local_fmin = tmp_local_intv->value.fval.min;
2633 local_fmax = tmp_local_intv->value.fval.max;
2634
2635 if ((local_fmin >= tmp_intv->value.fval.min) && (local_fmin <= tmp_intv->value.fval.max)) {
2636 if (local_fmax <= tmp_intv->value.fval.max) {
2637 tmp_local_intv = tmp_local_intv->next;
2638 continue;
2639 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002640 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002641 }
2642 }
2643 }
2644
2645 tmp_intv = tmp_intv->next;
2646 }
2647
2648 /* some interval left uncovered -> fail */
2649 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002650 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002651 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002652 }
2653
Michal Vaskoaeb51802016-04-11 10:58:47 +02002654 /* append the local intervals to all the intervals of the superior types, return it all */
2655 if (intv) {
2656 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2657 tmp_intv->next = local_intv;
2658 } else {
2659 intv = local_intv;
2660 }
2661 *ret = intv;
2662
2663 return EXIT_SUCCESS;
2664
2665error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002666 while (intv) {
2667 tmp_intv = intv->next;
2668 free(intv);
2669 intv = tmp_intv;
2670 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002671 while (local_intv) {
2672 tmp_local_intv = local_intv->next;
2673 free(local_intv);
2674 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002675 }
2676
Michal Vaskoaeb51802016-04-11 10:58:47 +02002677 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002678}
2679
Michal Vasko730dfdf2015-08-11 14:48:05 +02002680/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002681 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2682 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002683 *
2684 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002685 * @param[in] mod_name Typedef name module name.
2686 * @param[in] module Main module.
2687 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002688 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002689 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002690 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002691 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002692int
Michal Vasko1e62a092015-12-01 12:27:20 +01002693resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2694 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002695{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002696 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002697 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002698 int tpdf_size;
2699
Michal Vasko1dca6882015-10-22 14:29:42 +02002700 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002701 /* no prefix, try built-in types */
2702 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2703 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002704 if (ret) {
2705 *ret = ly_types[i].def;
2706 }
2707 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002708 }
2709 }
2710 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002711 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002712 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002713 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002714 }
2715 }
2716
Michal Vasko1dca6882015-10-22 14:29:42 +02002717 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002718 /* search in local typedefs */
2719 while (parent) {
2720 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002721 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002722 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2723 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002724 break;
2725
Radek Krejci76512572015-08-04 09:47:08 +02002726 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002727 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2728 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002729 break;
2730
Radek Krejci76512572015-08-04 09:47:08 +02002731 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002732 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2733 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002734 break;
2735
Radek Krejci76512572015-08-04 09:47:08 +02002736 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002737 case LYS_ACTION:
2738 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2739 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002740 break;
2741
Radek Krejci76512572015-08-04 09:47:08 +02002742 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002743 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2744 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002745 break;
2746
Radek Krejci76512572015-08-04 09:47:08 +02002747 case LYS_INPUT:
2748 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002749 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2750 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002751 break;
2752
2753 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002754 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002755 continue;
2756 }
2757
2758 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002759 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002760 match = &tpdf[i];
2761 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002762 }
2763 }
2764
Michal Vaskodcf98e62016-05-05 17:53:53 +02002765 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002766 }
Radek Krejcic071c542016-01-27 14:57:51 +01002767 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002768 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002769 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002770 if (!module) {
2771 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002772 }
2773 }
2774
2775 /* search in top level typedefs */
2776 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002777 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002778 match = &module->tpdf[i];
2779 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002780 }
2781 }
2782
2783 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002784 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002785 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002786 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002787 match = &module->inc[i].submodule->tpdf[j];
2788 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002789 }
2790 }
2791 }
2792
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002793 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002794
2795check_leafref:
2796 if (ret) {
2797 *ret = match;
2798 }
2799 if (match->type.base == LY_TYPE_LEAFREF) {
2800 while (!match->type.info.lref.path) {
2801 match = match->type.der;
2802 assert(match);
2803 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002804 }
2805 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002806}
2807
Michal Vasko1dca6882015-10-22 14:29:42 +02002808/**
2809 * @brief Check the default \p value of the \p type. Logs directly.
2810 *
2811 * @param[in] type Type definition to use.
2812 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002813 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002814 *
2815 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2816 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002818check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002819{
Radek Krejcibad2f172016-08-02 11:04:15 +02002820 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002821 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002822 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002823
Radek Krejcic13db382016-08-16 10:52:42 +02002824 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002825 /* the type was not resolved yet, nothing to do for now */
2826 return EXIT_FAILURE;
2827 }
2828
2829 if (!value) {
2830 /* we do not have a new default value, so is there any to check even, in some base type? */
2831 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2832 if (base_tpdf->dflt) {
2833 value = base_tpdf->dflt;
2834 break;
2835 }
2836 }
2837
2838 if (!value) {
2839 /* no default value, nothing to check, all is well */
2840 return EXIT_SUCCESS;
2841 }
2842
2843 /* so there is a default value in a base type, but can the default value be no longer valid (did we define some new restrictions)? */
2844 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002845 case LY_TYPE_IDENT:
2846 case LY_TYPE_INST:
2847 case LY_TYPE_LEAFREF:
2848 case LY_TYPE_BOOL:
2849 case LY_TYPE_EMPTY:
2850 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2851 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002852 case LY_TYPE_BITS:
2853 /* the default value must match the restricted list of values, if the type was restricted */
2854 if (type->info.bits.count) {
2855 break;
2856 }
2857 return EXIT_SUCCESS;
2858 case LY_TYPE_ENUM:
2859 /* the default value must match the restricted list of values, if the type was restricted */
2860 if (type->info.enums.count) {
2861 break;
2862 }
2863 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002864 case LY_TYPE_DEC64:
2865 if (type->info.dec64.range) {
2866 break;
2867 }
2868 return EXIT_SUCCESS;
2869 case LY_TYPE_BINARY:
2870 if (type->info.binary.length) {
2871 break;
2872 }
2873 return EXIT_SUCCESS;
2874 case LY_TYPE_INT8:
2875 case LY_TYPE_INT16:
2876 case LY_TYPE_INT32:
2877 case LY_TYPE_INT64:
2878 case LY_TYPE_UINT8:
2879 case LY_TYPE_UINT16:
2880 case LY_TYPE_UINT32:
2881 case LY_TYPE_UINT64:
2882 if (type->info.num.range) {
2883 break;
2884 }
2885 return EXIT_SUCCESS;
2886 case LY_TYPE_STRING:
2887 if (type->info.str.length || type->info.str.patterns) {
2888 break;
2889 }
2890 return EXIT_SUCCESS;
2891 case LY_TYPE_UNION:
2892 /* way too much trouble learning whether we need to check the default again, so just do it */
2893 break;
2894 default:
2895 LOGINT;
2896 return -1;
2897 }
Radek Krejci55a161c2016-09-05 17:13:25 +02002898 } else if (type->base == LY_TYPE_EMPTY) {
2899 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
2900 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
2901 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02002902 }
2903
Michal Vasko1dca6882015-10-22 14:29:42 +02002904 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01002905 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02002906 node.value_str = value;
2907 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01002908 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01002909 if (!node.schema) {
2910 LOGMEM;
2911 return -1;
2912 }
Radek Krejcibad2f172016-08-02 11:04:15 +02002913 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01002914 if (!node.schema->name) {
2915 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02002916 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01002917 return -1;
2918 }
Michal Vasko56826402016-03-02 11:11:37 +01002919 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01002920 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02002921
Radek Krejci37b756f2016-01-18 10:15:03 +01002922 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02002923 if (!type->info.lref.target) {
2924 ret = EXIT_FAILURE;
2925 goto finish;
2926 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002927 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02002928
2929 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
2930 /* it was converted to JSON format before, nothing else sensible we can do */
2931
2932 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02002933 if (lyp_parse_value(&node, NULL, 1)) {
2934 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02002935 if (base_tpdf) {
2936 /* default value was is defined in some base typedef */
2937 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
2938 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
2939 /* we have refined bits/enums */
2940 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
2941 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
2942 value, type->parent->name, base_tpdf->name);
2943 }
2944 }
Michal Vasko3767fb22016-07-21 12:10:57 +02002945 }
Michal Vasko1dca6882015-10-22 14:29:42 +02002946 }
2947
2948finish:
2949 if (node.value_type == LY_TYPE_BITS) {
2950 free(node.value.bit);
2951 }
2952 free((char *)node.schema->name);
2953 free(node.schema);
2954
2955 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002956}
2957
Michal Vasko730dfdf2015-08-11 14:48:05 +02002958/**
2959 * @brief Check a key for mandatory attributes. Logs directly.
2960 *
2961 * @param[in] key The key to check.
2962 * @param[in] flags What flags to check.
2963 * @param[in] list The list of all the keys.
2964 * @param[in] index Index of the key in the key list.
2965 * @param[in] name The name of the keys.
2966 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002967 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002968 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002969 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002971check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002972{
Radek Krejciadb57612016-02-16 13:34:34 +01002973 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002974 char *dup = NULL;
2975 int j;
2976
2977 /* existence */
2978 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02002979 if (name[len] != '\0') {
2980 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01002981 if (!dup) {
2982 LOGMEM;
2983 return -1;
2984 }
Michal Vaskof02e3742015-08-05 16:27:02 +02002985 dup[len] = '\0';
2986 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002987 }
Radek Krejci48464ed2016-03-17 15:44:09 +01002988 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02002989 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002990 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002991 }
2992
2993 /* uniqueness */
2994 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01002995 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01002996 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002997 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002998 }
2999 }
3000
3001 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003002 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003003 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003004 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003005 }
3006
3007 /* type of the leaf is not built-in empty */
3008 if (key->type.base == LY_TYPE_EMPTY) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003009 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003010 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003011 }
3012
3013 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003014 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003015 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003016 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003017 }
3018
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003019 /* key is not placed from augment */
3020 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003021 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3022 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003023 return -1;
3024 }
3025
Radek Krejci3f21ada2016-08-01 13:34:31 +02003026 /* key is not when/if-feature -conditional */
3027 j = 0;
3028 if (key->when || (key->iffeature_size && (j = 1))) {
3029 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3030 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3031 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003032 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003033 }
3034
Michal Vasko0b85aa82016-03-07 14:37:43 +01003035 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003036}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003037
3038/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003039 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003040 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003041 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003042 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003043 *
3044 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3045 */
3046int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003047resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003048{
Radek Krejci581ce772015-11-10 17:22:40 +01003049 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003050 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003051
Radek Krejcif3c71de2016-04-11 12:45:46 +02003052 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003053 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003054 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003055 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003056 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003057 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003058 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003059 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003060 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003061 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003062 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003063 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3064 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003065 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003066 }
Radek Krejci581ce772015-11-10 17:22:40 +01003067 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003068 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003069 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003070 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3071 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003072 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073 }
3074
Radek Krejcicf509982015-12-15 09:22:44 +01003075 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003076 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003077 return -1;
3078 }
3079
Radek Krejcid09d1a52016-08-11 14:05:45 +02003080 /* check that all unique's targets are of the same config type */
3081 if (*trg_type) {
3082 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3083 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3084 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3085 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3086 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3087 return -1;
3088 }
3089 } else {
3090 /* first unique */
3091 if (leaf->flags & LYS_CONFIG_W) {
3092 *trg_type = 1;
3093 } else {
3094 *trg_type = 2;
3095 }
3096 }
3097
Radek Krejcica7efb72016-01-18 13:06:01 +01003098 /* set leaf's unique flag */
3099 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3100
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003101 return EXIT_SUCCESS;
3102
3103error:
3104
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003105 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003106}
3107
Radek Krejci0c0086a2016-03-24 15:20:28 +01003108void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003109unres_data_del(struct unres_data *unres, uint32_t i)
3110{
3111 /* there are items after the one deleted */
3112 if (i+1 < unres->count) {
3113 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003114 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003115
3116 /* deleting the last item */
3117 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003118 free(unres->node);
3119 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003120 }
3121
3122 /* if there are no items after and it is not the last one, just move the counter */
3123 --unres->count;
3124}
3125
Michal Vasko0491ab32015-08-19 14:28:29 +02003126/**
3127 * @brief Resolve (find) a data node from a specific module. Does not log.
3128 *
3129 * @param[in] mod Module to search in.
3130 * @param[in] name Name of the data node.
3131 * @param[in] nam_len Length of the name.
3132 * @param[in] start Data node to start the search from.
3133 * @param[in,out] parents Resolved nodes. If there are some parents,
3134 * they are replaced (!!) with the resolvents.
3135 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003136 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003137 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003139resolve_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 +02003140{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003141 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003142 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003143 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144
Michal Vasko23b61ec2015-08-19 11:19:50 +02003145 if (!parents->count) {
3146 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003147 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003148 if (!parents->node) {
3149 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003150 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003151 }
Michal Vaskocf024702015-10-08 15:01:42 +02003152 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003153 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003154 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003155 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003157 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003158 continue;
3159 }
3160 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003161 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3163 && node->schema->name[nam_len] == '\0') {
3164 /* matching target */
3165 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003166 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003167 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003168 flag = 1;
3169 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003170 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003171 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003172 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3173 if (!parents->node) {
3174 return EXIT_FAILURE;
3175 }
Michal Vaskocf024702015-10-08 15:01:42 +02003176 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003177 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003178 }
3179 }
3180 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003181
3182 if (!flag) {
3183 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003184 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003185 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003186 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003187 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188 }
3189
Michal Vasko0491ab32015-08-19 14:28:29 +02003190 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003191}
3192
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003193/**
3194 * @brief Resolve (find) a data node. Does not log.
3195 *
Radek Krejci581ce772015-11-10 17:22:40 +01003196 * @param[in] mod_name Module name of the data node.
3197 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 * @param[in] name Name of the data node.
3199 * @param[in] nam_len Length of the name.
3200 * @param[in] start Data node to start the search from.
3201 * @param[in,out] parents Resolved nodes. If there are some parents,
3202 * they are replaced (!!) with the resolvents.
3203 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003204 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003205 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003206static int
Radek Krejci581ce772015-11-10 17:22:40 +01003207resolve_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 +02003208 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003209{
Michal Vasko1e62a092015-12-01 12:27:20 +01003210 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003211 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003212
Michal Vasko23b61ec2015-08-19 11:19:50 +02003213 assert(start);
3214
Michal Vasko31fc3672015-10-21 12:08:13 +02003215 if (mod_name) {
3216 /* we have mod_name, find appropriate module */
3217 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003218 if (!str) {
3219 LOGMEM;
3220 return -1;
3221 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003222 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3223 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003224 if (!mod) {
3225 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003226 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003227 }
3228 } else {
3229 /* no prefix, module is the same as of current node */
3230 mod = start->schema->module;
3231 }
3232
3233 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234}
3235
Michal Vasko730dfdf2015-08-11 14:48:05 +02003236/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003237 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003238 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003239 *
Michal Vaskobb211122015-08-19 14:03:11 +02003240 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003241 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003242 * @param[in,out] node_match Nodes satisfying the restriction
3243 * without the predicate. Nodes not
3244 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003245 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003246 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003247 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003248 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003249static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003250resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003251 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003253 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003254 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003256 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3257 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003258 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003259 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003260
3261 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003262 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003263 if (!source_match.node) {
3264 LOGMEM;
3265 return -1;
3266 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003267 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003268 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003269 if (!dest_match.node) {
3270 LOGMEM;
3271 return -1;
3272 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273
3274 do {
3275 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3276 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003277 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003278 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003279 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003280 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003281 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282 pred += i;
3283
Michal Vasko23b61ec2015-08-19 11:19:50 +02003284 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003286 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003287
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003288 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003289 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003290 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003291 i = 0;
3292 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003293 }
3294
3295 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003296 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003297 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3299 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003300 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003301 rc = -1;
3302 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003303 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003304 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003305 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003306 dest_match.node[0] = dest_match.node[0]->parent;
3307 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003308 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003309 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003310 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003311 }
3312 }
3313 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003314 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003315 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003316 i = 0;
3317 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318 }
3319
3320 if (pke_len == pke_parsed) {
3321 break;
3322 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003323 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 +02003324 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003325 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003326 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003327 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003328 }
3329 pke_parsed += i;
3330 }
3331
3332 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003333 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3334 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3335 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3336 }
3337 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3338 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3339 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3340 }
3341 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003342 goto remove_leafref;
3343 }
3344
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003345 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003346 goto remove_leafref;
3347 }
3348
3349 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003350 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351 continue;
3352
3353remove_leafref:
3354 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003355 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 }
3357 } while (has_predicate);
3358
Michal Vaskocf024702015-10-08 15:01:42 +02003359 free(source_match.node);
3360 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003361 if (parsed) {
3362 *parsed = parsed_loc;
3363 }
3364 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003365
3366error:
3367
3368 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003369 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003370 }
3371 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003372 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003373 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003374 if (parsed) {
3375 *parsed = -parsed_loc+i;
3376 }
3377 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003378}
3379
Michal Vasko730dfdf2015-08-11 14:48:05 +02003380/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003381 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003382 *
Michal Vaskocf024702015-10-08 15:01:42 +02003383 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003384 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003385 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003386 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003387 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003388 */
Michal Vasko184521f2015-09-24 13:14:26 +02003389static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003390resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391{
Radek Krejci71b795b2015-08-10 16:20:39 +02003392 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003393 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003394 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003395 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396
Michal Vaskocf024702015-10-08 15:01:42 +02003397 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003398
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003400 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003401
3402 /* searching for nodeset */
3403 do {
3404 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003405 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003406 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407 goto error;
3408 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003410 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003411
Michal Vasko23b61ec2015-08-19 11:19:50 +02003412 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003413 if (parent_times > 0) {
3414 data = node;
3415 for (i = 1; i < parent_times; ++i) {
3416 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003417 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003418 } else if (!parent_times) {
3419 data = node->child;
3420 } else {
3421 /* absolute path */
3422 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 }
3424
Michal Vaskobfd98e62016-09-02 09:50:05 +02003425 /* we may still be parsing it and the pointer is not correct yet */
3426 if (data->prev) {
3427 while (data->prev->next) {
3428 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003429 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003430 }
3431 }
3432
3433 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003434 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003435 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003436 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003437 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438 goto error;
3439 }
3440
3441 if (has_predicate) {
3442 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003443 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003444 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3445 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003446 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003447 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003448 continue;
3449 }
3450
3451 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003452 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003454 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003455 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003456 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003457 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003458 goto error;
3459 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003461 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462
Michal Vasko23b61ec2015-08-19 11:19:50 +02003463 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003464 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 goto error;
3466 }
3467 }
3468 } while (path[0] != '\0');
3469
Michal Vaskof02e3742015-08-05 16:27:02 +02003470 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471
3472error:
3473
Michal Vaskocf024702015-10-08 15:01:42 +02003474 free(ret->node);
3475 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003476 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477
Michal Vasko0491ab32015-08-19 14:28:29 +02003478 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479}
3480
Michal Vasko730dfdf2015-08-11 14:48:05 +02003481/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003482 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003483 *
Michal Vaskobb211122015-08-19 14:03:11 +02003484 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003485 * @param[in] context_node Predicate context node (where the predicate is placed).
3486 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003487 *
Michal Vasko184521f2015-09-24 13:14:26 +02003488 * @return 0 on forward reference, otherwise the number
3489 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003490 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003491 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003492static int
Radek Krejciadb57612016-02-16 13:34:34 +01003493resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Radek Krejci48464ed2016-03-17 15:44:09 +01003494 struct lys_node *parent)
Michal Vasko1f76a282015-08-04 16:16:53 +02003495{
Michal Vasko1e62a092015-12-01 12:27:20 +01003496 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003497 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3498 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 +02003499 int has_predicate, dest_parent_times = 0, i, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003500
3501 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003502 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003503 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003504 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003505 return -parsed+i;
3506 }
3507 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003508 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003509
Michal Vasko58090902015-08-13 14:04:15 +02003510 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003511 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003512 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003513 }
Radek Krejciadb57612016-02-16 13:34:34 +01003514 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003515 LYS_LEAF | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003516 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003517 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003518 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003519 }
3520
3521 /* destination */
3522 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3523 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003524 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 +02003525 return -parsed;
3526 }
3527 pke_parsed += i;
3528
Radek Krejciadb57612016-02-16 13:34:34 +01003529 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003530 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003531 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003532 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003533 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02003534 /* path is supposed to be evaluated in data tree, so we have to skip
3535 * all schema nodes that cannot be instantiated in data tree */
3536 for (dst_node = lys_parent(dst_node);
3537 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST));
3538 dst_node = lys_parent(dst_node));
Michal Vasko1f76a282015-08-04 16:16:53 +02003539 }
3540 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003541 if (!dest_pref) {
3542 dest_pref = dst_node->module->name;
3543 }
3544 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003545 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003546 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003547 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003548 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003549 }
3550
3551 if (pke_len == pke_parsed) {
3552 break;
3553 }
3554
3555 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3556 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003557 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003558 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003559 return -parsed;
3560 }
3561 pke_parsed += i;
3562 }
3563
3564 /* check source - dest match */
Michal Vasko184521f2015-09-24 13:14:26 +02003565 if (dst_node->nodetype != LYS_LEAF) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003566 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Radek Krejci48464ed2016-03-17 15:44:09 +01003567 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
3568 "Destination node is not a leaf, but %s.", strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003569 return -parsed;
3570 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003571 } while (has_predicate);
3572
3573 return parsed;
3574}
3575
Michal Vasko730dfdf2015-08-11 14:48:05 +02003576/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003577 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003578 *
Michal Vaskobb211122015-08-19 14:03:11 +02003579 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003580 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003581 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3582 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003583 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003584 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003585 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003586 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003587static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003588resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003589 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003590{
Michal Vasko1e62a092015-12-01 12:27:20 +01003591 const struct lys_node *node;
Radek Krejcic071c542016-01-27 14:57:51 +01003592 const struct lys_module *mod;
Michal Vasko1f76a282015-08-04 16:16:53 +02003593 const char *id, *prefix, *name;
3594 int pref_len, nam_len, parent_times, has_predicate;
Michal Vasko184521f2015-09-24 13:14:26 +02003595 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003596
Michal Vasko184521f2015-09-24 13:14:26 +02003597 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003598 parent_times = 0;
3599 id = path;
3600
3601 do {
3602 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003603 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 +02003604 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003605 }
3606 id += i;
3607
Michal Vasko184521f2015-09-24 13:14:26 +02003608 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003609 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003610 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003611 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejcic071c542016-01-27 14:57:51 +01003612 /* get start node */
3613 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003614 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003615 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3616 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003617 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003618 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003619 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003620 if (parent_tpdf) {
3621 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003622 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003623 return -1;
3624 }
3625
Michal Vaskodf053d12016-07-21 13:33:31 +02003626 /* node is the parent already, skip one ".." */
3627 for (i = 1, node = parent; i < parent_times; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003628 /* path is supposed to be evaluated in data tree, so we have to skip
3629 * all schema nodes that cannot be instantiated in data tree */
3630 for (node = lys_parent(node);
3631 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST));
3632 node = lys_parent(node));
3633
Michal Vasko1f76a282015-08-04 16:16:53 +02003634 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003635 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3636 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003637 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003638 }
Michal Vasko58090902015-08-13 14:04:15 +02003639
Michal Vasko1f76a282015-08-04 16:16:53 +02003640 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003641 } else {
3642 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003643 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003644 }
Michal Vasko36cbaa42015-12-14 13:15:48 +01003645
Michal Vasko184521f2015-09-24 13:14:26 +02003646 first_iter = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003648 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003649 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003650 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 +01003651 return -1;
3652 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003653 node = node->child;
3654 }
3655
Michal Vasko4f0dad02016-02-15 14:08:23 +01003656 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003657 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003658 }
3659
Michal Vasko36cbaa42015-12-14 13:15:48 +01003660 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 +02003661 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003662 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003663 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003664 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003665
3666 if (has_predicate) {
3667 /* we have predicate, so the current result must be list */
3668 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003669 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003670 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003671 }
3672
Radek Krejci48464ed2016-03-17 15:44:09 +01003673 i = resolve_path_predicate_schema(id, node, parent);
Michal Vasko184521f2015-09-24 13:14:26 +02003674 if (!i) {
Michal Vaskof9664da2015-08-24 15:03:30 +02003675 return EXIT_FAILURE;
Michal Vasko184521f2015-09-24 13:14:26 +02003676 } else if (i < 0) {
3677 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003678 }
3679 id += i;
3680 }
3681 } while (id[0]);
3682
Michal Vaskoca917682016-07-25 11:00:37 +02003683 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3684 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003685 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003686 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3687 "Leafref target \"%s\" is not a leaf%s.", path,
3688 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003689 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003690 }
3691
Radek Krejcicf509982015-12-15 09:22:44 +01003692 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003693 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003694 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003695 return -1;
3696 }
3697
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003698 if (ret) {
3699 *ret = node;
3700 }
3701 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003702}
3703
Michal Vasko730dfdf2015-08-11 14:48:05 +02003704/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003705 * @brief Resolve instance-identifier predicate in JSON data format.
3706 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003707 *
Michal Vaskobb211122015-08-19 14:03:11 +02003708 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003709 * @param[in,out] node_match Nodes matching the restriction without
3710 * the predicate. Nodes not satisfying
3711 * the predicate are removed.
3712 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003713 * @return Number of characters successfully parsed,
3714 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003715 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003716static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003717resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003718{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003719 /* ... /node[target = value] ... */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003720 struct unres_data target_match;
3721 struct ly_ctx *ctx;
Michal Vasko1e62a092015-12-01 12:27:20 +01003722 const struct lys_module *mod;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003723 const char *model, *name, *value;
3724 char *str;
3725 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed;
3726 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003727
Michal Vasko1f2cc332015-08-19 11:18:32 +02003728 assert(pred && node_match->count);
3729
Michal Vaskocf024702015-10-08 15:01:42 +02003730 ctx = node_match->node[0]->schema->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003731 idx = -1;
3732 parsed = 0;
3733
3734 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003735 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003736 return -parsed+i;
3737 }
3738 parsed += i;
3739 pred += i;
3740
Michal Vasko1f2cc332015-08-19 11:18:32 +02003741 /* pos */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003742 if (isdigit(name[0])) {
3743 idx = atoi(name);
3744 }
3745
Michal Vasko1f2cc332015-08-19 11:18:32 +02003746 for (cur_idx = 0, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003747 /* target */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003748 memset(&target_match, 0, sizeof target_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003749 if ((name[0] == '.') || !value) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003750 target_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003751 target_match.node = malloc(sizeof *target_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003752 if (!target_match.node) {
3753 LOGMEM;
3754 return -1;
3755 }
Michal Vaskocf024702015-10-08 15:01:42 +02003756 target_match.node[0] = node_match->node[j];
Michal Vasko1f2cc332015-08-19 11:18:32 +02003757 } else {
3758 str = strndup(model, mod_len);
3759 mod = ly_ctx_get_module(ctx, str, NULL);
3760 free(str);
3761
Radek Krejci804836a2016-02-03 10:39:55 +01003762 if (resolve_data(mod, name, nam_len, node_match->node[j]->child, &target_match)) {
Michal Vasko1f2cc332015-08-19 11:18:32 +02003763 goto remove_instid;
3764 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003765 }
3766
3767 /* check that we have the correct type */
3768 if (name[0] == '.') {
Michal Vaskocf024702015-10-08 15:01:42 +02003769 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003770 goto remove_instid;
3771 }
3772 } else if (value) {
Michal Vaskocf024702015-10-08 15:01:42 +02003773 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003774 goto remove_instid;
3775 }
3776 }
3777
Michal Vasko83a6c462015-10-08 16:43:53 +02003778 if ((value && (strncmp(((struct lyd_node_leaf_list *)target_match.node[0])->value_str, value, val_len)
3779 || ((struct lyd_node_leaf_list *)target_match.node[0])->value_str[val_len]))
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003780 || (!value && (idx != cur_idx))) {
3781 goto remove_instid;
3782 }
3783
Michal Vaskocf024702015-10-08 15:01:42 +02003784 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003785
3786 /* leafref is ok, continue check with next leafref */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003787 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003788 continue;
3789
3790remove_instid:
Michal Vaskocf024702015-10-08 15:01:42 +02003791 free(target_match.node);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003792
3793 /* does not fulfill conditions, remove leafref record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003794 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003795 }
3796 } while (has_predicate);
3797
3798 return parsed;
3799}
3800
Michal Vasko730dfdf2015-08-11 14:48:05 +02003801/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003802 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003803 *
Radek Krejciadb57612016-02-16 13:34:34 +01003804 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02003805 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003806 *
Radek Krejcic5090c32015-08-12 09:46:19 +02003807 * @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 +02003808 */
Michal Vasko184521f2015-09-24 13:14:26 +02003809static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01003810resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003811{
Radek Krejcic5090c32015-08-12 09:46:19 +02003812 int i = 0, j;
3813 struct lyd_node *result = NULL;
Michal Vaskobea08e92016-05-18 13:28:08 +02003814 const struct lys_module *mod, *prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003815 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003816 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02003817 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003818 int mod_len, name_len, has_predicate;
3819 struct unres_data node_match;
3820 uint32_t k;
3821
3822 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003823
Radek Krejcic5090c32015-08-12 09:46:19 +02003824 /* we need root to resolve absolute path */
3825 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02003826 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02003827 if (data->prev) {
3828 for (; data->prev->next; data = data->prev);
3829 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003830
Michal Vaskobea08e92016-05-18 13:28:08 +02003831 prev_mod = lyd_node_module(data);
3832
Radek Krejcic5090c32015-08-12 09:46:19 +02003833 /* search for the instance node */
3834 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02003835 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02003836 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003837 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003838 goto error;
3839 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003840 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003841
Michal Vaskobea08e92016-05-18 13:28:08 +02003842 if (model) {
3843 str = strndup(model, mod_len);
3844 if (!str) {
3845 LOGMEM;
3846 goto error;
3847 }
3848 mod = ly_ctx_get_module(ctx, str, NULL);
3849 free(str);
3850 } else {
3851 mod = prev_mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02003852 }
3853
Michal Vasko1f2cc332015-08-19 11:18:32 +02003854 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003855 /* no instance exists */
3856 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003857 }
3858
3859 if (has_predicate) {
3860 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003861 for (k = 0; k < node_match.count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003862 if ((node_match.node[k]->schema->nodetype == LYS_LIST &&
3863 ((struct lys_node_list *)node_match.node[k]->schema)->keys)
3864 || (node_match.node[k]->schema->nodetype == LYS_LEAFLIST)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003865 /* instid is ok, continue check with next instid */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003866 ++k;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003867 continue;
3868 }
3869
3870 /* does not fulfill conditions, remove inst record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003871 unres_data_del(&node_match, k);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003872 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003873
Michal Vaskof39142b2015-10-21 11:40:05 +02003874 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02003875 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003876 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003877 goto error;
3878 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02003879 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02003880
Michal Vasko1f2cc332015-08-19 11:18:32 +02003881 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003882 /* no instance exists */
3883 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003884 }
3885 }
Michal Vaskobea08e92016-05-18 13:28:08 +02003886
3887 prev_mod = mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003888 }
3889
Michal Vasko1f2cc332015-08-19 11:18:32 +02003890 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003891 /* no instance exists */
3892 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003893 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02003894 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01003895 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Radek Krejcic5090c32015-08-12 09:46:19 +02003896
Michal Vaskod6adbaa2016-04-11 11:01:09 +02003897 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02003898 } else {
3899 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003900 result = node_match.node[0];
3901 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003902
3903 return result;
3904 }
3905
3906error:
3907
3908 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02003909 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02003910
3911 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003912}
3913
Michal Vasko730dfdf2015-08-11 14:48:05 +02003914/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003915 * @brief Passes config flag down to children, skips nodes without config flags.
3916 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003917 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003918 * @param[in] node Siblings and their children to have flags changed.
Pavol Vican47319932016-08-29 09:14:47 +02003919 * @param[in] ignore Flag to ignore check if parent is LYS_NOTIF, LYS_INPUT, LYS_OUTPUT, LYS_RPC.
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003920 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02003921 *
3922 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003923 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02003924static int
Pavol Vican47319932016-08-29 09:14:47 +02003925inherit_config_flag(struct lys_node *node, int ignore, int flags)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003926{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003927 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02003928 LY_TREE_FOR(node, node) {
Pavol Vican47319932016-08-29 09:14:47 +02003929 if (!ignore && (node->flags & LYS_CONFIG_SET)) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003930 /* skip nodes with an explicit config value */
Michal Vaskoa86508c2016-08-26 14:30:19 +02003931 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
3932 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
3933 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
3934 return -1;
3935 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003936 continue;
3937 }
3938 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
Radek Krejci43f548d2016-06-16 11:06:38 +02003939 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02003940 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02003941 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Pavol Vican47319932016-08-29 09:14:47 +02003942 if (inherit_config_flag(node->child, ignore, flags)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02003943 return -1;
3944 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02003945 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003946 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02003947
3948 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003949}
3950
Michal Vasko730dfdf2015-08-11 14:48:05 +02003951/**
Michal Vasko7178e692016-02-12 15:58:05 +01003952 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003953 *
Michal Vaskobb211122015-08-19 14:03:11 +02003954 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01003955 * @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 +02003956 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003957 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003958 */
Michal Vasko7178e692016-02-12 15:58:05 +01003959static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003960resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003961{
Pavol Vican47319932016-08-29 09:14:47 +02003962 int rc, ignore_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02003963 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02003964 const struct lys_node *aug_target, *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003965
Michal Vasko15b36692016-08-26 15:29:54 +02003966 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003967
Michal Vasko15b36692016-08-26 15:29:54 +02003968 /* resolve target node */
3969 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
3970 if (rc == -1) {
3971 return -1;
3972 }
3973 if (rc > 0) {
3974 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
3975 return -1;
3976 }
3977 if (!aug_target) {
3978 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
3979 return EXIT_FAILURE;
3980 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003981
Michal Vasko15b36692016-08-26 15:29:54 +02003982 if (!aug->child) {
3983 /* nothing to do */
3984 LOGWRN("Augment \"%s\" without children.", aug->target_name);
3985 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003986 }
3987
Michal Vaskod58d5962016-03-02 14:29:41 +01003988 /* check for mandatory nodes - if the target node is in another module
3989 * the added nodes cannot be mandatory
3990 */
Michal Vasko15b36692016-08-26 15:29:54 +02003991 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02003992 && (rc = lyp_check_mandatory_augment(aug))) {
3993 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01003994 }
3995
Michal Vasko07e89ef2016-03-03 13:28:57 +01003996 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02003997 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01003998 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003999 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004000 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4001 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004002 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004003 return -1;
4004 }
4005 }
Michal Vasko15b36692016-08-26 15:29:54 +02004006 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004007 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004008 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004009 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4010 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004011 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004012 return -1;
4013 }
4014 }
4015 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004016 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004017 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004018 return -1;
4019 }
4020
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004021 /* inherit config information from actual parent */
Pavol Vican47319932016-08-29 09:14:47 +02004022 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = parent->parent);
4023 ignore_config = (parent) ? 1 : 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004024 LY_TREE_FOR(aug->child, sub) {
Pavol Vican47319932016-08-29 09:14:47 +02004025 if (inherit_config_flag(sub, ignore_config, aug_target->flags & LYS_CONFIG_MASK)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004026 return -1;
4027 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004028 }
4029
Radek Krejcic071c542016-01-27 14:57:51 +01004030 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004031 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004032 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004033 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004034 }
4035 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036
Michal Vasko15b36692016-08-26 15:29:54 +02004037 /* finally reconnect augmenting data into the target - add them to the target child list,
4038 * by setting aug->target we know the augment is fully resolved now */
4039 aug->target = (struct lys_node *)aug_target;
4040 if (aug->target->child) {
4041 sub = aug->target->child->prev; /* remember current target's last node */
4042 sub->next = aug->child; /* connect augmenting data after target's last node */
4043 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4044 aug->child->prev = sub; /* finish connecting of both child lists */
4045 } else {
4046 aug->target->child = aug->child;
4047 }
4048
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049 return EXIT_SUCCESS;
4050}
4051
Michal Vasko730dfdf2015-08-11 14:48:05 +02004052/**
Pavol Vican855ca622016-09-05 13:07:54 +02004053 * @brief Resolve (find) choice default case. Does not log.
4054 *
4055 * @param[in] choic Choice to use.
4056 * @param[in] dflt Name of the default case.
4057 *
4058 * @return Pointer to the default node or NULL.
4059 */
4060static struct lys_node *
4061resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4062{
4063 struct lys_node *child, *ret;
4064
4065 LY_TREE_FOR(choic->child, child) {
4066 if (child->nodetype == LYS_USES) {
4067 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4068 if (ret) {
4069 return ret;
4070 }
4071 }
4072
4073 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
4074 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST))) {
4075 return child;
4076 }
4077 }
4078
4079 return NULL;
4080}
4081
4082/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004083 * @brief Resolve uses, apply augments, refines. Logs directly.
4084 *
Michal Vaskobb211122015-08-19 14:03:11 +02004085 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004086 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004087 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004088 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004089 */
Michal Vasko184521f2015-09-24 13:14:26 +02004090static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004091resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004092{
4093 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004094 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004095 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004096 struct lys_node_leaflist *llist;
4097 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004098 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004099 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004100 struct lys_iffeature *iff, **old_iff;
Pavol Vican855ca622016-09-05 13:07:54 +02004101 int i, j, k, rc, parent_config, ignore_config;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004102 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004103 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004104
Michal Vasko71e1aa82015-08-12 12:17:51 +02004105 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004106 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004107 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004108
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004109 if (!uses->grp->child) {
4110 /* grouping without children, warning was already displayed */
4111 return EXIT_SUCCESS;
4112 }
4113
4114 /* get proper parent (config) flags */
4115 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4116 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004117 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004118 } else {
4119 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004120 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004121 }
4122
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004123 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004124 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004125 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, 0, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004126 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004127 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4128 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004129 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004130 }
Pavol Vican55abd332016-07-12 15:54:49 +02004131 /* test the name of siblings */
4132 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004133 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004134 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004135 }
4136 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004137 }
4138 ctx = uses->module->ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004139 for(parent = node; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = parent->parent);
4140 ignore_config = (parent) ? 1 : 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004141
Michal Vaskoa86508c2016-08-26 14:30:19 +02004142 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004143 assert(uses->child);
Pavol Vican47319932016-08-29 09:14:47 +02004144 if (inherit_config_flag(uses->child, ignore_config, parent_config)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004145 goto fail;
4146 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004147 }
4148
Michal Vaskodef0db12015-10-07 13:22:48 +02004149 /* we managed to copy the grouping, the rest must be possible to resolve */
4150
Pavol Vican855ca622016-09-05 13:07:54 +02004151 if (uses->refine_size) {
4152 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4153 if (!refine_nodes) {
4154 LOGMEM;
4155 goto fail;
4156 }
4157 }
4158
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004159 /* apply refines */
4160 for (i = 0; i < uses->refine_size; i++) {
4161 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004162 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004163 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004164 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004165 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004166 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004167 }
4168
Radek Krejci1d82ef62015-08-07 14:44:40 +02004169 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004170 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4171 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004172 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004173 }
Pavol Vican855ca622016-09-05 13:07:54 +02004174 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004175
4176 /* description on any nodetype */
4177 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004178 lydict_remove(ctx, node->dsc);
4179 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004180 }
4181
4182 /* reference on any nodetype */
4183 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004184 lydict_remove(ctx, node->ref);
4185 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004186 }
4187
4188 /* config on any nodetype */
Pavol Vican855ca622016-09-05 13:07:54 +02004189 if ((rfn->flags & LYS_CONFIG_MASK) && !ignore_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004190 node->flags &= ~LYS_CONFIG_MASK;
4191 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004192 }
4193
4194 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004195 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004196 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004197 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004198 leaf = (struct lys_node_leaf *)node;
4199
4200 lydict_remove(ctx, leaf->dflt);
4201 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4202
4203 /* check the default value */
4204 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004205 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004206 }
Radek Krejci200bf712016-08-16 17:11:04 +02004207 } else if (node->nodetype == LYS_LEAFLIST) {
4208 /* leaf-list */
4209 llist = (struct lys_node_leaflist *)node;
4210
4211 /* remove complete set of defaults in target */
4212 for (i = 0; i < llist->dflt_size; i++) {
4213 lydict_remove(ctx, llist->dflt[i]);
4214 }
4215 free(llist->dflt);
4216
4217 /* copy the default set from refine */
4218 llist->dflt_size = rfn->dflt_size;
4219 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4220 for (i = 0; i < llist->dflt_size; i++) {
4221 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4222 }
4223
4224 /* check default value */
4225 for (i = 0; i < llist->dflt_size; i++) {
4226 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004227 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004228 }
4229 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004230 }
4231 }
4232
4233 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004234 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004235 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004236 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004237 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004238
4239 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004240 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004241 }
Pavol Vican855ca622016-09-05 13:07:54 +02004242 if (rfn->flags & LYS_MAND_TRUE) {
4243 /* check if node has default value */
4244 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4245 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4246 goto fail;
4247 }
4248 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4249 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4250 goto fail;
4251 }
4252 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004253 }
4254
4255 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004256 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4257 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4258 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004259 }
4260
4261 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004262 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004263 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004264 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004265 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004266 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004267 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004268 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004269 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004270 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004271 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004272 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004273 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004274 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004275 }
4276 }
4277
4278 /* must in leaf, leaf-list, list, container or anyxml */
4279 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004280 switch (node->nodetype) {
4281 case LYS_LEAF:
4282 old_size = &((struct lys_node_leaf *)node)->must_size;
4283 old_must = &((struct lys_node_leaf *)node)->must;
4284 break;
4285 case LYS_LEAFLIST:
4286 old_size = &((struct lys_node_leaflist *)node)->must_size;
4287 old_must = &((struct lys_node_leaflist *)node)->must;
4288 break;
4289 case LYS_LIST:
4290 old_size = &((struct lys_node_list *)node)->must_size;
4291 old_must = &((struct lys_node_list *)node)->must;
4292 break;
4293 case LYS_CONTAINER:
4294 old_size = &((struct lys_node_container *)node)->must_size;
4295 old_must = &((struct lys_node_container *)node)->must;
4296 break;
4297 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004298 case LYS_ANYDATA:
4299 old_size = &((struct lys_node_anydata *)node)->must_size;
4300 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004301 break;
4302 default:
4303 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004304 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004305 }
4306
4307 size = *old_size + rfn->must_size;
4308 must = realloc(*old_must, size * sizeof *rfn->must);
4309 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004310 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004311 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004312 }
Pavol Vican855ca622016-09-05 13:07:54 +02004313 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4314 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4315 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4316 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4317 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4318 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004319 }
4320
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004321 *old_must = must;
4322 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004323
4324 /* check XPath dependencies again */
4325 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4326 goto fail;
4327 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004328 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004329
4330 /* if-feature in leaf, leaf-list, list, container or anyxml */
4331 if (rfn->iffeature_size) {
4332 old_size = &node->iffeature_size;
4333 old_iff = &node->iffeature;
4334
4335 size = *old_size + rfn->iffeature_size;
4336 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4337 if (!iff) {
4338 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004339 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004340 }
Pavol Vican855ca622016-09-05 13:07:54 +02004341 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4342 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004343 if (usize1) {
4344 /* there is something to duplicate */
4345 /* duplicate compiled expression */
4346 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4347 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004348 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004349
4350 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004351 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4352 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004353 }
4354 }
4355
4356 *old_iff = iff;
4357 *old_size = size;
4358 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004359 }
4360
4361 /* apply augments */
4362 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004363 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004364 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004365 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004366 }
4367 }
4368
Pavol Vican855ca622016-09-05 13:07:54 +02004369 /* check refines */
4370 for (i = 0; i < uses->refine_size; i++) {
4371 node = refine_nodes[i];
4372 rfn = &uses->refine[i];
4373
4374 /* config on any nodetype */
4375 if ((rfn->flags & LYS_CONFIG_MASK) && !ignore_config) {
4376 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4377 if (parent && parent->nodetype != LYS_GROUPING &&
4378 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4379 (rfn->flags & LYS_CONFIG_W)) {
4380 /* setting config true under config false is prohibited */
4381 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4382 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4383 "changing config from 'false' to 'true' is prohibited while "
4384 "the target's parent is still config 'false'.");
4385 goto fail;
4386 }
4387
4388 /* inherit config change to the target children */
4389 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4390 if (rfn->flags & LYS_CONFIG_W) {
4391 if (iter->flags & LYS_CONFIG_SET) {
4392 /* config is set explicitely, go to next sibling */
4393 next = NULL;
4394 goto nextsibling;
4395 }
4396 } else { /* LYS_CONFIG_R */
4397 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4398 /* error - we would have config data under status data */
4399 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4400 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4401 "changing config from 'true' to 'false' is prohibited while the target "
4402 "has still a children with explicit config 'true'.");
4403 goto fail;
4404 }
4405 }
4406 /* change config */
4407 iter->flags &= ~LYS_CONFIG_MASK;
4408 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4409
4410 /* select next iter - modified LY_TREE_DFS_END */
4411 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4412 next = NULL;
4413 } else {
4414 next = iter->child;
4415 }
4416nextsibling:
4417 if (!next) {
4418 /* try siblings */
4419 next = iter->next;
4420 }
4421 while (!next) {
4422 /* parent is already processed, go to its sibling */
4423 iter = lys_parent(iter);
4424
4425 /* no siblings, go back through parents */
4426 if (iter == node) {
4427 /* we are done, no next element to process */
4428 break;
4429 }
4430 next = iter->next;
4431 }
4432 }
4433 }
4434
4435 /* default value */
4436 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4437 /* choice */
4438
4439 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4440 rfn->dflt[0]);
4441 if (!((struct lys_node_choice *)node)->dflt) {
4442 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4443 goto fail;
4444 }
4445 if (lyp_check_mandatory_choice(node)) {
4446 goto fail;
4447 }
4448 }
4449
4450 /* min/max-elements on list or leaf-list */
4451 if (node->nodetype == LYS_LIST) {
4452 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4453 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4454 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4455 goto fail;
4456 }
4457 } else if (node->nodetype == LYS_LEAFLIST) {
4458 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4459 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4460 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4461 goto fail;
4462 }
4463 }
4464
4465 /* additional checks */
4466 if (node->nodetype == LYS_LEAFLIST) {
4467 llist = (struct lys_node_leaflist *)node;
4468 if (llist->dflt_size && llist->min) {
4469 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4470 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4471 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4472 goto fail;
4473 }
4474 }
4475 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4476 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4477 for (parent = node->parent;
4478 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4479 parent = parent->parent) {
4480 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4481 /* stop also on presence containers */
4482 break;
4483 }
4484 }
4485 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4486 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4487 if (lyp_check_mandatory_choice(parent)) {
4488 goto fail;
4489 }
4490 }
4491 }
4492 }
4493 free(refine_nodes);
4494
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004495 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004496
4497fail:
4498 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4499 lys_node_free(iter, NULL, 0);
4500 }
Pavol Vican855ca622016-09-05 13:07:54 +02004501 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004502 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004503}
4504
Radek Krejci018f1f52016-08-03 16:01:20 +02004505static int
4506identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4507{
4508 int i;
4509
4510 assert(der && base);
4511
4512 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4513 if (!base->der) {
4514 LOGMEM;
4515 return EXIT_FAILURE;
4516 }
4517 base->der[base->der_size++] = der;
4518
4519 for (i = 0; i < base->base_size; i++) {
4520 if (identity_backlink_update(der, base->base[i])) {
4521 return EXIT_FAILURE;
4522 }
4523 }
4524
4525 return EXIT_SUCCESS;
4526}
4527
Michal Vasko730dfdf2015-08-11 14:48:05 +02004528/**
4529 * @brief Resolve base identity recursively. Does not log.
4530 *
4531 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004532 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004533 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004534 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004535 *
Radek Krejci219fa612016-08-15 10:36:51 +02004536 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004537 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004538static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004539resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004540 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004541{
Michal Vaskof02e3742015-08-05 16:27:02 +02004542 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004543 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004544
Radek Krejcicf509982015-12-15 09:22:44 +01004545 assert(ret);
4546
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004547 /* search module */
4548 for (i = 0; i < module->ident_size; i++) {
4549 if (!strcmp(basename, module->ident[i].name)) {
4550
4551 if (!ident) {
4552 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004553 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004554 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004555 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004556 }
4557
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004558 base = &module->ident[i];
4559 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004560 }
4561 }
4562
4563 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004564 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4565 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4566 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004567
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004568 if (!ident) {
4569 *ret = &module->inc[j].submodule->ident[i];
4570 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004571 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004572
4573 base = &module->inc[j].submodule->ident[i];
4574 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004575 }
4576 }
4577 }
4578
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004579matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004580 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004581 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004582 /* is it already completely resolved? */
4583 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004584 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004585 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4586
4587 /* simple check for circular reference,
4588 * the complete check is done as a side effect of using only completely
4589 * resolved identities (previous check of unres content) */
4590 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4591 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4592 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004593 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004594 }
4595
Radek Krejci06f64ed2016-08-15 11:07:44 +02004596 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004597 }
4598 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004599
Radek Krejcibabbff82016-02-19 13:31:37 +01004600 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004601 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004602 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603 }
4604
Radek Krejci219fa612016-08-15 10:36:51 +02004605 /* base not found (maybe a forward reference) */
4606 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004607}
4608
Michal Vasko730dfdf2015-08-11 14:48:05 +02004609/**
4610 * @brief Resolve base identity. Logs directly.
4611 *
4612 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004613 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004614 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004615 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004616 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004617 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004618 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004619 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004620static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004621resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004622 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004623{
4624 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004625 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004626 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004627 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004628 struct lys_module *mod;
4629
4630 assert((ident && !type) || (!ident && type));
4631
4632 if (!type) {
4633 /* have ident to resolve */
4634 ret = &target;
4635 flags = ident->flags;
4636 mod = ident->module;
4637 } else {
4638 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004639 ++type->info.ident.count;
4640 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4641 if (!type->info.ident.ref) {
4642 LOGMEM;
4643 return -1;
4644 }
4645
4646 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004647 flags = type->parent->flags;
4648 mod = type->parent->module;
4649 }
Michal Vaskof2006002016-04-21 16:28:15 +02004650 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004651
4652 /* search for the base identity */
4653 name = strchr(basename, ':');
4654 if (name) {
4655 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004656 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004657 name++;
4658
Michal Vasko2d851a92015-10-20 16:16:36 +02004659 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004660 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004661 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004662 }
4663 } else {
4664 name = basename;
4665 }
4666
Radek Krejcic071c542016-01-27 14:57:51 +01004667 /* get module where to search */
4668 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4669 if (!module) {
4670 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004671 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004672 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004673 }
4674
Radek Krejcic071c542016-01-27 14:57:51 +01004675 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004676 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4677 if (!rc) {
4678 assert(*ret);
4679
4680 /* check status */
4681 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4682 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
4683 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004684 } else {
4685 if (ident) {
4686 ident->base[ident->base_size++] = *ret;
4687
4688 /* maintain backlinks to the derived identities */
4689 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
4690 }
Radek Krejci219fa612016-08-15 10:36:51 +02004691 }
4692 } else if (rc == EXIT_FAILURE) {
4693 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02004694 if (type) {
4695 --type->info.ident.count;
4696 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004697 }
4698
Radek Krejci219fa612016-08-15 10:36:51 +02004699 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004700}
4701
Michal Vasko730dfdf2015-08-11 14:48:05 +02004702/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004703 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004704 *
Michal Vaskof2d43962016-09-02 11:10:16 +02004705 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02004706 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01004707 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02004708 *
4709 * @return Pointer to the identity resolvent, NULL on error.
4710 */
Radek Krejcia52656e2015-08-05 13:41:50 +02004711struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02004712resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004713{
Michal Vaskoc633ca02015-08-21 14:03:51 +02004714 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02004715 int mod_name_len, rc, i, j;
4716 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004717
Michal Vaskof2d43962016-09-02 11:10:16 +02004718 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004719 return NULL;
4720 }
4721
Michal Vaskoc633ca02015-08-21 14:03:51 +02004722 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004723 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004724 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004725 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01004726 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01004727 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02004728 return NULL;
4729 }
4730
Michal Vaskof2d43962016-09-02 11:10:16 +02004731 /* go through all the bases in all the derived types */
4732 while (type->der) {
4733 for (i = 0; i < type->info.ident.count; ++i) {
4734 cur = type->info.ident.ref[i];
4735 if (!strcmp(cur->name, name) && (!mod_name
4736 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
4737 goto match;
4738 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02004739
Michal Vaskof2d43962016-09-02 11:10:16 +02004740 for (j = 0; j < cur->der_size; j++) {
4741 der = cur->der[j]; /* shortcut */
4742 if (!strcmp(der->name, name) &&
4743 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
4744 /* we have match */
4745 cur = der;
4746 goto match;
4747 }
4748 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004749 }
Michal Vaskof2d43962016-09-02 11:10:16 +02004750 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004751 }
4752
Radek Krejci48464ed2016-03-17 15:44:09 +01004753 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004754 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004755
4756match:
Michal Vaskof2d43962016-09-02 11:10:16 +02004757 for (i = 0; i < cur->iffeature_size; i++) {
4758 if (!resolve_iffeature(&cur->iffeature[i])) {
4759 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004760 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02004761 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02004762 return NULL;
4763 }
4764 }
Michal Vaskof2d43962016-09-02 11:10:16 +02004765 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004766}
4767
Michal Vasko730dfdf2015-08-11 14:48:05 +02004768/**
Michal Vaskobb211122015-08-19 14:03:11 +02004769 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004770 *
Michal Vaskobb211122015-08-19 14:03:11 +02004771 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004772 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004773 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004774 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004775 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004776static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004777resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004778{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004779 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01004780 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02004781
Radek Krejci010e54b2016-03-15 09:40:34 +01004782 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
4783 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
4784 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
4785 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
4786 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02004787 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoe91afce2015-08-12 12:21:00 +02004788
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004789 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01004790 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
4791 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004792 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "grouping", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004793 return -1;
4794 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004795 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01004796 return -1;
4797 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004798 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004799 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
4800 * (and smaller flags - it uses only a limited set of flags)
4801 */
4802 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004803 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004804 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01004805 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02004806 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004807 }
4808
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004809 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01004810 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004811 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004812 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02004813 } else {
4814 /* instantiate grouping only when it is completely resolved */
4815 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02004816 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004817 return EXIT_FAILURE;
4818 }
4819
Radek Krejci48464ed2016-03-17 15:44:09 +01004820 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004821 if (!rc) {
4822 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01004823 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004824 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004825 LOGINT;
4826 return -1;
4827 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02004828 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01004829 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004830 }
Radek Krejcicf509982015-12-15 09:22:44 +01004831
4832 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004833 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01004834 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004835 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004836 return -1;
4837 }
4838
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004839 return EXIT_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01004840 } else if ((rc == EXIT_FAILURE) && par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02004841 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01004842 uses->flags |= LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004843 }
4844
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004845 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004846}
4847
Michal Vasko730dfdf2015-08-11 14:48:05 +02004848/**
Michal Vasko9957e592015-08-17 15:04:09 +02004849 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004850 *
Michal Vaskobb211122015-08-19 14:03:11 +02004851 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004852 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004853 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004854 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004855 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004856static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004857resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004858{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004859 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01004860 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004861
4862 for (i = 0; i < list->keys_size; ++i) {
4863 /* get the key name */
4864 if ((value = strpbrk(keys_str, " \t\n"))) {
4865 len = value - keys_str;
4866 while (isspace(value[0])) {
4867 value++;
4868 }
4869 } else {
4870 len = strlen(keys_str);
4871 }
4872
Radek Krejcic4283442016-04-22 09:19:27 +02004873 rc = lys_get_sibling(list->child, lys_main_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004874 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02004875 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
4876 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004877 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004878
Radek Krejci48464ed2016-03-17 15:44:09 +01004879 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004880 /* check_key logs */
4881 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004882 }
4883
Radek Krejcicf509982015-12-15 09:22:44 +01004884 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01004885 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004886 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
4887 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01004888 return -1;
4889 }
4890
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004891 /* prepare for next iteration */
4892 while (value && isspace(value[0])) {
4893 value++;
4894 }
4895 keys_str = value;
4896 }
4897
Michal Vaskof02e3742015-08-05 16:27:02 +02004898 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004899}
4900
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004901/**
Michal Vaskobf19d252015-10-08 15:39:17 +02004902 * @brief Resolve (check) all must conditions of \p node.
4903 * Logs directly.
4904 *
4905 * @param[in] node Data node with optional must statements.
Michal Vaskobf19d252015-10-08 15:39:17 +02004906 *
4907 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
4908 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004909static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004910resolve_must(struct lyd_node *node)
Michal Vaskof02e3742015-08-05 16:27:02 +02004911{
Michal Vaskobf19d252015-10-08 15:39:17 +02004912 uint8_t i, must_size;
4913 struct lys_restr *must;
4914 struct lyxp_set set;
4915
4916 assert(node);
4917 memset(&set, 0, sizeof set);
4918
4919 switch (node->schema->nodetype) {
4920 case LYS_CONTAINER:
4921 must_size = ((struct lys_node_container *)node->schema)->must_size;
4922 must = ((struct lys_node_container *)node->schema)->must;
4923 break;
4924 case LYS_LEAF:
4925 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
4926 must = ((struct lys_node_leaf *)node->schema)->must;
4927 break;
4928 case LYS_LEAFLIST:
4929 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
4930 must = ((struct lys_node_leaflist *)node->schema)->must;
4931 break;
4932 case LYS_LIST:
4933 must_size = ((struct lys_node_list *)node->schema)->must_size;
4934 must = ((struct lys_node_list *)node->schema)->must;
4935 break;
4936 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004937 case LYS_ANYDATA:
4938 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
4939 must = ((struct lys_node_anydata *)node->schema)->must;
Michal Vaskobf19d252015-10-08 15:39:17 +02004940 break;
4941 default:
4942 must_size = 0;
4943 break;
4944 }
4945
4946 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02004947 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02004948 return -1;
4949 }
4950
Michal Vasko944a5642016-03-21 11:48:58 +01004951 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02004952
Michal Vasko8146d4c2016-05-09 15:50:29 +02004953 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02004954 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
4955 if (must[i].emsg) {
4956 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
4957 }
4958 if (must[i].eapptag) {
4959 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
4960 }
Michal Vaskobf19d252015-10-08 15:39:17 +02004961 return 1;
4962 }
4963 }
4964
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004965 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02004966}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004967
Michal Vaskobf19d252015-10-08 15:39:17 +02004968/**
Michal Vasko508a50d2016-09-07 14:50:33 +02004969 * @brief Resolve (find) when condition schema context node. Does not log.
4970 *
4971 * @param[in] schema Schema node with the when condition.
4972 * @param[out] ctx_snode When schema context node.
4973 * @param[out] ctx_snode_type Schema context node type.
4974 */
4975void
4976resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
4977{
4978 const struct lys_node *sparent;
4979
4980 /* find a not schema-only node */
4981 *ctx_snode_type = LYXP_NODE_ELEM;
4982 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
4983 if (schema->nodetype == LYS_AUGMENT) {
4984 sparent = ((struct lys_node_augment *)schema)->target;
4985 } else {
4986 sparent = schema->parent;
4987 }
4988 if (!sparent) {
4989 /* context node is the document root (fake root in our case) */
4990 if (schema->flags & LYS_CONFIG_W) {
4991 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
4992 } else {
4993 *ctx_snode_type = LYXP_NODE_ROOT_STATE;
4994 }
4995 /* move the fake root to the beginning of the list, if any */
4996 while (schema->prev->next) {
4997 schema = schema->prev;
4998 }
4999 break;
5000 }
5001 schema = sparent;
5002 }
5003
5004 *ctx_snode = (struct lys_node *)schema;
5005}
5006
5007/**
Michal Vaskocf024702015-10-08 15:01:42 +02005008 * @brief Resolve (find) when condition context node. Does not log.
5009 *
5010 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005011 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005012 * @param[out] ctx_node Context node.
5013 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005014 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005015 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005016 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005017static int
5018resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5019 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005020{
Michal Vaskocf024702015-10-08 15:01:42 +02005021 struct lyd_node *parent;
5022 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005023 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005024 uint16_t i, data_depth, schema_depth;
5025
Michal Vasko508a50d2016-09-07 14:50:33 +02005026 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005027
5028 /* get node depths */
5029 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
Michal Vaskoe3655562016-08-24 15:56:17 +02005030 for (sparent = schema, schema_depth = 0;
5031 sparent;
5032 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02005033 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
Michal Vaskocf024702015-10-08 15:01:42 +02005034 ++schema_depth;
5035 }
5036 }
5037 if (data_depth < schema_depth) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005038 return -1;
Michal Vaskocf024702015-10-08 15:01:42 +02005039 }
5040
Michal Vasko956e8542016-08-26 09:43:35 +02005041 if (schema_depth) {
5042 /* find the corresponding data node */
5043 for (i = 0; i < data_depth - schema_depth; ++i) {
5044 node = node->parent;
5045 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005046 if (node->schema != schema) {
5047 return -1;
5048 }
Michal Vaskocf024702015-10-08 15:01:42 +02005049 }
5050
Michal Vaskoa59495d2016-08-22 09:18:58 +02005051 *ctx_node = node;
5052 *ctx_node_type = node_type;
5053 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005054}
5055
Michal Vasko76c3bd32016-08-24 16:02:52 +02005056/**
5057 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5058 * The context nodes is adjusted if needed.
5059 *
5060 * @param[in] snode Schema node, whose children instances need to be unlinked.
5061 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5062 * it is moved to point to another sibling still in the original tree.
5063 * @param[in,out] ctx_node When context node, adjusted if needed.
5064 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5065 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5066 * Ordering may change, but there will be no semantic change.
5067 *
5068 * @return EXIT_SUCCESS on success, -1 on error.
5069 */
5070static int
5071resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5072 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5073{
5074 struct lyd_node *next, *elem;
5075
5076 switch (snode->nodetype) {
5077 case LYS_AUGMENT:
5078 case LYS_USES:
5079 case LYS_CHOICE:
5080 case LYS_CASE:
5081 LY_TREE_FOR(snode->child, snode) {
5082 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5083 return -1;
5084 }
5085 }
5086 break;
5087 case LYS_CONTAINER:
5088 case LYS_LIST:
5089 case LYS_LEAF:
5090 case LYS_LEAFLIST:
5091 case LYS_ANYXML:
5092 case LYS_ANYDATA:
5093 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5094 if (elem->schema == snode) {
5095
5096 if (elem == *ctx_node) {
5097 /* We are going to unlink our context node! This normally cannot happen,
5098 * but we use normal top-level data nodes for faking a document root node,
5099 * so if this is the context node, we just use the next top-level node.
5100 * Additionally, it can even happen that there are no top-level data nodes left,
5101 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5102 * lyxp_eval() can handle this special situation.
5103 */
5104 if (ctx_node_type == LYXP_NODE_ELEM) {
5105 LOGINT;
5106 return -1;
5107 }
5108
5109 if (elem->prev == elem) {
5110 /* unlinking last top-level element, use an empty data tree */
5111 *ctx_node = NULL;
5112 } else {
5113 /* in this case just use the previous/last top-level data node */
5114 *ctx_node = elem->prev;
5115 }
5116 } else if (elem == *node) {
5117 /* We are going to unlink the currently processed node. This does not matter that
5118 * much, but we would lose access to the original data tree, so just move our
5119 * pointer somewhere still inside it.
5120 */
5121 if ((*node)->prev != *node) {
5122 *node = (*node)->prev;
5123 } else {
5124 /* the processed node with sibings were all unlinked, oh well */
5125 *node = NULL;
5126 }
5127 }
5128
5129 /* temporarily unlink the node */
5130 lyd_unlink(elem);
5131 if (*unlinked_nodes) {
5132 if (lyd_insert_after(*unlinked_nodes, elem)) {
5133 LOGINT;
5134 return -1;
5135 }
5136 } else {
5137 *unlinked_nodes = elem;
5138 }
5139
5140 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5141 /* there can be only one instance */
5142 break;
5143 }
5144 }
5145 }
5146 break;
5147 default:
5148 LOGINT;
5149 return -1;
5150 }
5151
5152 return EXIT_SUCCESS;
5153}
5154
5155/**
5156 * @brief Relink the unlinked nodes back.
5157 *
5158 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5159 * we simply need a sibling from the original data tree.
5160 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5161 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5162 * or the sibling of \p unlinked_nodes.
5163 *
5164 * @return EXIT_SUCCESS on success, -1 on error.
5165 */
5166static int
5167resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5168{
5169 struct lyd_node *elem;
5170
5171 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5172 if (ctx_node_type == LYXP_NODE_ELEM) {
5173 if (lyd_insert(node, elem)) {
5174 return -1;
5175 }
5176 } else {
5177 if (lyd_insert_after(node, elem)) {
5178 return -1;
5179 }
5180 }
5181 }
5182
5183 return EXIT_SUCCESS;
5184}
5185
Radek Krejci03b71f72016-03-16 11:10:09 +01005186int
Radek Krejci46165822016-08-26 14:06:27 +02005187resolve_applies_must(const struct lys_node *schema)
Radek Krejci01696bf2016-03-18 13:19:36 +01005188{
Radek Krejci46165822016-08-26 14:06:27 +02005189 assert(schema);
5190
5191 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005192 case LYS_CONTAINER:
Radek Krejci46165822016-08-26 14:06:27 +02005193 return ((struct lys_node_container *)schema)->must_size;
Radek Krejci01696bf2016-03-18 13:19:36 +01005194 case LYS_LEAF:
Radek Krejci46165822016-08-26 14:06:27 +02005195 return ((struct lys_node_leaf *)schema)->must_size;
Radek Krejci01696bf2016-03-18 13:19:36 +01005196 case LYS_LEAFLIST:
Radek Krejci46165822016-08-26 14:06:27 +02005197 return ((struct lys_node_leaflist *)schema)->must_size;
Radek Krejci01696bf2016-03-18 13:19:36 +01005198 case LYS_LIST:
Radek Krejci46165822016-08-26 14:06:27 +02005199 return ((struct lys_node_list *)schema)->must_size;
Radek Krejci01696bf2016-03-18 13:19:36 +01005200 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005201 case LYS_ANYDATA:
Radek Krejci46165822016-08-26 14:06:27 +02005202 return ((struct lys_node_anydata *)schema)->must_size;
Radek Krejci01696bf2016-03-18 13:19:36 +01005203 default:
5204 return 0;
5205 }
5206}
5207
5208int
Radek Krejci46165822016-08-26 14:06:27 +02005209resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005210{
Radek Krejci46165822016-08-26 14:06:27 +02005211 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005212
Radek Krejci46165822016-08-26 14:06:27 +02005213 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005214
Radek Krejci46165822016-08-26 14:06:27 +02005215 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005216 return 1;
5217 }
5218
Radek Krejci46165822016-08-26 14:06:27 +02005219 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005220 goto check_augment;
5221
Radek Krejci46165822016-08-26 14:06:27 +02005222 while (parent) {
5223 /* stop conditions */
5224 if (!mode) {
5225 /* stop on node that can be instantiated in data tree */
5226 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5227 break;
5228 }
5229 } else {
5230 /* stop on the specified node */
5231 if (parent == stop) {
5232 break;
5233 }
5234 }
5235
5236 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005237 return 1;
5238 }
5239check_augment:
5240
5241 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005242 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005243 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005244 }
5245 parent = lys_parent(parent);
5246 }
5247
5248 return 0;
5249}
5250
Michal Vaskocf024702015-10-08 15:01:42 +02005251/**
5252 * @brief Resolve (check) all when conditions relevant for \p node.
5253 * Logs directly.
5254 *
5255 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005256 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005257 * @return
5258 * -1 - error, ly_errno is set
5259 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005260 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005261 * 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 +02005262 */
Radek Krejci46165822016-08-26 14:06:27 +02005263int
5264resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005265{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005266 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005267 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005268 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005269 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005270 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005271
5272 assert(node);
5273 memset(&set, 0, sizeof set);
5274
5275 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005276 /* make the node dummy for the evaluation */
5277 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005278 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005279 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005280 if (rc) {
5281 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005282 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005283 }
Radek Krejci51093642016-03-29 10:14:59 +02005284 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005285 }
5286
Radek Krejci03b71f72016-03-16 11:10:09 +01005287 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005288 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005289 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005290 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005291 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005292 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005293 }
Radek Krejci51093642016-03-29 10:14:59 +02005294
5295 /* free xpath set content */
5296 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005297 }
5298
Michal Vasko90fc2a32016-08-24 15:58:58 +02005299 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005300 goto check_augment;
5301
5302 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005303 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5304 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005305 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005306 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005307 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005308 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005309 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005310 }
5311 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005312
5313 unlinked_nodes = NULL;
5314 /* we do not want our node pointer to change */
5315 tmp_node = node;
5316 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5317 if (rc) {
5318 goto cleanup;
5319 }
5320
5321 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5322
5323 if (unlinked_nodes && ctx_node) {
5324 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5325 rc = -1;
5326 goto cleanup;
5327 }
5328 }
5329
Radek Krejci03b71f72016-03-16 11:10:09 +01005330 if (rc) {
5331 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005332 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005333 }
Radek Krejci51093642016-03-29 10:14:59 +02005334 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005335 }
5336
Michal Vasko944a5642016-03-21 11:48:58 +01005337 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005338 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005339 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005340 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005341 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005342 }
Radek Krejci51093642016-03-29 10:14:59 +02005343
5344 /* free xpath set content */
5345 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005346 }
5347
5348check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005349 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005350 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005351 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005352 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005353 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005354 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005355 }
5356 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005357
5358 unlinked_nodes = NULL;
5359 tmp_node = node;
5360 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5361 if (rc) {
5362 goto cleanup;
5363 }
5364
5365 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5366
5367 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5368 * so the tree did not actually change and there is nothing for us to do
5369 */
5370 if (unlinked_nodes && ctx_node) {
5371 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5372 rc = -1;
5373 goto cleanup;
5374 }
5375 }
5376
Radek Krejci03b71f72016-03-16 11:10:09 +01005377 if (rc) {
5378 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005379 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005380 }
Radek Krejci51093642016-03-29 10:14:59 +02005381 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005382 }
5383
Michal Vasko944a5642016-03-21 11:48:58 +01005384 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005385
Michal Vasko8146d4c2016-05-09 15:50:29 +02005386 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005387 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005388 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005389 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005390 }
Radek Krejci51093642016-03-29 10:14:59 +02005391
5392 /* free xpath set content */
5393 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005394 }
5395
Michal Vasko90fc2a32016-08-24 15:58:58 +02005396 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005397 }
5398
Radek Krejci0b7704f2016-03-18 12:16:14 +01005399 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005400
Radek Krejci51093642016-03-29 10:14:59 +02005401cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005402 /* free xpath set content */
5403 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5404
Radek Krejci46165822016-08-26 14:06:27 +02005405 if (result) {
5406 if (node->when_status & LYD_WHEN_TRUE) {
5407 *result = 1;
5408 } else {
5409 *result = 0;
5410 }
5411 }
5412
Radek Krejci51093642016-03-29 10:14:59 +02005413 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005414}
5415
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005416/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005417 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
5418 *
5419 * @param[in] node Node to examine.
5420 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5421 */
5422static int
5423check_xpath(struct lys_node *node)
5424{
5425 struct lys_node *parent, *elem;
5426 struct lyxp_set set;
5427 uint32_t i;
5428 int rc;
5429
5430 parent = node;
5431 while (parent) {
5432 if (parent->nodetype == LYS_GROUPING) {
5433 /* unresolved grouping, skip for now */
5434 return 0;
5435 }
5436 if (parent->nodetype == LYS_AUGMENT) {
5437 if (!((struct lys_node_augment *)parent)->target) {
5438 /* uresolved augment skip for now */
5439 return 0;
5440 } else {
5441 parent = ((struct lys_node_augment *)parent)->target;
5442 continue;
5443 }
5444 }
5445 parent = parent->parent;
5446 }
5447
5448 rc = lyxp_node_atomize(node, &set);
5449 if (rc) {
5450 return rc;
5451 }
5452
5453 /* RPC, action can have neither must nor when */
5454 for (parent = node; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
5455
5456 if (parent) {
5457 for (i = 0; i < set.used; ++i) {
5458 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
5459 if (!elem) {
5460 /* not in node's input, output, or, notification subtree, set the flag */
5461 node->flags |= LYS_XPATH_DEP;
5462 break;
5463 }
5464 }
5465 }
5466
5467 free(set.val.snodes);
5468 return EXIT_SUCCESS;
5469}
5470
5471/**
Michal Vaskobb211122015-08-19 14:03:11 +02005472 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005473 *
5474 * @param[in] mod Main module.
5475 * @param[in] item Item to resolve. Type determined by \p type.
5476 * @param[in] type Type of the unresolved item.
5477 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005478 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005479 *
5480 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5481 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005482static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005483resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005484 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005485{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005486 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005487 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5488 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005489 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005490 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005491
Radek Krejcic79c6b12016-07-26 15:11:49 +02005492 struct ly_set *refs, *procs;
5493 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005494 struct lys_ident *ident;
5495 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005496 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005497 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005498 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005499 struct unres_list_uniq *unique_info;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005500
5501 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005502 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005503 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005504 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005505 ident = item;
5506
Radek Krejci018f1f52016-08-03 16:01:20 +02005507 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005508 break;
5509 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005510 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005511 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005512 stype = item;
5513
Radek Krejci018f1f52016-08-03 16:01:20 +02005514 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005515 break;
5516 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005517 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005518 stype = item;
5519
Radek Krejci2f12f852016-01-08 12:59:57 +01005520 /* HACK - when there is no parent, we are in top level typedef and in that
5521 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5522 * know it via tpdf_flag */
5523 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005524 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005525 node = (struct lys_node *)stype->parent;
5526 }
5527
Radek Krejci48464ed2016-03-17 15:44:09 +01005528 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005529 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005530 if (!tpdf_flag && !rc) {
5531 assert(stype->info.lref.target);
Radek Krejci46c4cd72016-01-21 15:13:52 +01005532 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005533 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5534 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005535 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005536 }
5537
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005538 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005539 case UNRES_TYPE_DER_TPDF:
5540 tpdf_flag = 1;
5541 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005542 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005543 /* parent */
5544 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005545 stype = item;
5546
Michal Vasko88c29542015-11-27 14:57:53 +01005547 /* HACK type->der is temporarily unparsed type statement */
5548 yin = (struct lyxml_elem *)stype->der;
5549 stype->der = NULL;
5550
Pavol Vicana0e4e672016-02-24 12:20:04 +01005551 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5552 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005553 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005554
5555 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005556 /* may try again later */
5557 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005558 } else {
5559 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005560 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005561 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005562 }
5563
Michal Vasko88c29542015-11-27 14:57:53 +01005564 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005565 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005566 if (!rc) {
5567 /* we need to always be able to free this, it's safe only in this case */
5568 lyxml_free(mod->ctx, yin);
5569 } else {
5570 /* may try again later, put all back how it was */
5571 stype->der = (struct lys_tpdf *)yin;
5572 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005573 }
Radek Krejcic13db382016-08-16 10:52:42 +02005574 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02005575 /* it does not make sense to have leaf-list of empty type */
5576 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
5577 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
5578 }
Radek Krejcic13db382016-08-16 10:52:42 +02005579 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_INGRP) {
5580 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
5581 * by uses statement until the type is resolved. We do that the same way as uses statements inside
5582 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
5583 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
5584 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_INGRP is used as value
5585 * of the type's base member. */
5586 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
5587 if (par_grp) {
5588 ((struct lys_node_grp *)par_grp)->nacm++;
5589 stype->base = LY_TYPE_INGRP;
5590 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02005591 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005592 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005593 case UNRES_IFFEAT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005594 node = str_snode;
Radek Krejci9ff0a922016-07-14 13:08:05 +02005595 expr = *((const char **)item);
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005596
Radek Krejci9ff0a922016-07-14 13:08:05 +02005597 rc = resolve_feature(expr, strlen(expr), node, item);
5598 if (!rc) {
5599 /* success */
5600 free((char *)expr);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005601 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005602 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02005603 case UNRES_FEATURE:
5604 feat = (struct lys_feature *)item;
5605
5606 if (feat->iffeature_size) {
5607 refs = ly_set_new();
5608 procs = ly_set_new();
5609 ly_set_add(procs, feat, 0);
5610
5611 while (procs->number) {
5612 ref = procs->set.g[procs->number - 1];
5613 ly_set_rm_index(procs, procs->number - 1);
5614
5615 for (i = 0; i < ref->iffeature_size; i++) {
5616 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
5617 for (; j > 0 ; j--) {
Michal Vasko878e38d2016-09-05 12:17:53 +02005618 if (unres_schema_find(unres, -1, &ref->iffeature[i].features[j - 1], UNRES_IFFEAT) == -1) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02005619 if (ref->iffeature[i].features[j - 1] == feat) {
5620 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
5621 goto featurecheckdone;
5622 }
5623
5624 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
5625 k = refs->number;
5626 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
5627 /* not yet seen feature, add it for processing */
5628 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
5629 }
5630 }
5631 } else {
5632 /* forward reference */
5633 rc = EXIT_FAILURE;
5634 goto featurecheckdone;
5635 }
5636 }
5637
5638 }
5639 }
5640 rc = EXIT_SUCCESS;
5641
5642featurecheckdone:
5643 ly_set_free(refs);
5644 ly_set_free(procs);
5645 }
5646
5647 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005648 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01005649 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005650 break;
5651 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005652 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005653 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005654 stype = item;
5655
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005656 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005657 break;
5658 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005659 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005660 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005661 choic = item;
5662
Radek Krejcie00d2312016-08-12 15:27:49 +02005663 if (!choic->dflt) {
5664 choic->dflt = resolve_choice_dflt(choic, expr);
5665 }
Michal Vasko7955b362015-09-04 14:18:15 +02005666 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02005667 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02005668 } else {
5669 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005670 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005671 break;
5672 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01005673 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01005674 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005675 break;
5676 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02005677 unique_info = (struct unres_list_uniq *)item;
5678 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005679 break;
Michal Vasko7178e692016-02-12 15:58:05 +01005680 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005681 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01005682 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02005683 case UNRES_XPATH:
5684 node = (struct lys_node *)item;
5685 rc = check_xpath(node);
5686 break;
Michal Vaskocf024702015-10-08 15:01:42 +02005687 default:
5688 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005689 break;
5690 }
5691
Radek Krejci54081ce2016-08-12 15:21:47 +02005692 if (has_str && !rc) {
5693 /* the string is no more needed in case of success.
5694 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01005695 lydict_remove(mod->ctx, str_snode);
5696 }
5697
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005698 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005699}
5700
Michal Vaskof02e3742015-08-05 16:27:02 +02005701/* logs directly */
5702static void
Radek Krejci48464ed2016-03-17 15:44:09 +01005703print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005704{
Michal Vaskocb34dc62016-05-20 14:38:37 +02005705 struct lyxml_elem *xml;
5706 struct lyxml_attr *attr;
Radek Krejci76e15e12016-06-22 11:02:24 +02005707 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02005708
Michal Vaskof02e3742015-08-05 16:27:02 +02005709 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02005710 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005711 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005712 break;
5713 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01005714 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005715 break;
5716 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01005717 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
5718 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02005719 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005720 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02005721 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02005722 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
5723 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
5724 type_name = ((struct yang_type *)xml)->name;
5725 } else {
5726 LY_TREE_FOR(xml->attr, attr) {
5727 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
5728 type_name = attr->value;
5729 break;
5730 }
5731 }
5732 assert(attr);
5733 }
5734 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02005735 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02005736 case UNRES_IFFEAT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005737 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", (char *)item);
Michal Vaskof02e3742015-08-05 16:27:02 +02005738 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02005739 case UNRES_FEATURE:
5740 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
5741 ((struct lys_feature *)item)->name);
5742 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02005743 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01005744 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02005745 break;
5746 case UNRES_TYPE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005747 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005748 break;
5749 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005750 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005751 break;
5752 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01005753 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005754 break;
5755 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01005756 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02005757 break;
Michal Vasko7178e692016-02-12 15:58:05 +01005758 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01005759 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
5760 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01005761 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02005762 case UNRES_XPATH:
5763 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
5764 (char *)str_node, ((struct lys_node *)item)->name);
5765 break;
Michal Vaskocf024702015-10-08 15:01:42 +02005766 default:
5767 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02005768 break;
5769 }
5770}
5771
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005772/**
Michal Vaskobb211122015-08-19 14:03:11 +02005773 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005774 *
5775 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005776 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005777 *
Michal Vasko92b8a382015-08-19 14:03:49 +02005778 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005779 */
Michal Vaskof02e3742015-08-05 16:27:02 +02005780int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005781resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02005782{
Radek Krejci010e54b2016-03-15 09:40:34 +01005783 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005784 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005785
5786 assert(unres);
5787
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005788 LOGVRB("Resolving unresolved schema nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01005789 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02005790
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005791 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02005792 do {
Michal Vasko88c29542015-11-27 14:57:53 +01005793 unres_count = 0;
5794 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02005795
5796 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005797 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02005798 * if-features are resolved here to make sure that we will have all if-features for
5799 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02005800 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02005801 continue;
5802 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005803 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02005804 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02005805
Michal Vasko88c29542015-11-27 14:57:53 +01005806 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01005807 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005808 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02005809 unres->type[i] = UNRES_RESOLVED;
5810 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01005811 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02005812 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005813 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02005814 /* print the error */
5815 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005816 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02005817 } else {
5818 /* forward reference, erase ly_errno */
5819 ly_errno = LY_SUCCESS;
5820 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02005821 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005822 }
Michal Vasko88c29542015-11-27 14:57:53 +01005823 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02005824
Michal Vasko88c29542015-11-27 14:57:53 +01005825 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02005826 /* just print the errors */
5827 ly_vlog_hide(0);
5828
5829 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005830 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02005831 continue;
5832 }
5833 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci8a8d5ff2016-07-27 14:08:38 +02005834
5835 /* free the allocated resources */
5836 if (unres->type[i] == UNRES_IFFEAT) {
5837 free(*((char **)unres->item[i]));
5838 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02005839 }
Michal Vasko92b8a382015-08-19 14:03:49 +02005840 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005841 }
5842
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005843 /* the rest */
5844 for (i = 0; i < unres->count; ++i) {
5845 if (unres->type[i] == UNRES_RESOLVED) {
5846 continue;
5847 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02005848
Radek Krejci48464ed2016-03-17 15:44:09 +01005849 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01005850 if (rc == 0) {
5851 unres->type[i] = UNRES_RESOLVED;
5852 ++resolved;
5853 } else if (rc == -1) {
5854 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02005855 /* print the error */
5856 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
5857 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005858 }
5859 }
5860
Radek Krejci010e54b2016-03-15 09:40:34 +01005861 ly_vlog_hide(0);
5862
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005863 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005864 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
5865 * all the validation errors
5866 */
5867 for (i = 0; i < unres->count; ++i) {
5868 if (unres->type[i] == UNRES_RESOLVED) {
5869 continue;
5870 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005871 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01005872 }
Michal Vasko92b8a382015-08-19 14:03:49 +02005873 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005874 }
5875
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02005876 LOGVRB("All schema nodes and constraints resolved.");
Radek Krejcic071c542016-01-27 14:57:51 +01005877 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005878 return EXIT_SUCCESS;
5879}
5880
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005881/**
Michal Vaskobb211122015-08-19 14:03:11 +02005882 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005883 *
5884 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005885 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005886 * @param[in] item Item to resolve. Type determined by \p type.
5887 * @param[in] type Type of the unresolved item.
5888 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005889 *
Michal Vasko3767fb22016-07-21 12:10:57 +02005890 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005891 */
5892int
Radek Krejci48464ed2016-03-17 15:44:09 +01005893unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
5894 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005895{
Radek Krejci54081ce2016-08-12 15:21:47 +02005896 int rc;
5897 const char *dictstr;
5898
5899 dictstr = lydict_insert(mod->ctx, str, 0);
5900 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
5901
5902 if (rc == -1) {
5903 lydict_remove(mod->ctx, dictstr);
5904 }
5905 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005906}
5907
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005908/**
Michal Vaskobb211122015-08-19 14:03:11 +02005909 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005910 *
5911 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005912 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005913 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01005914 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005915 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005916 *
Michal Vasko3767fb22016-07-21 12:10:57 +02005917 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005918 */
5919int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005920unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01005921 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005922{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005923 int rc;
Michal Vasko88c29542015-11-27 14:57:53 +01005924 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01005925 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005926
Michal Vasko9bf425b2015-10-22 11:42:03 +02005927 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
5928 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005929
Radek Krejci010e54b2016-03-15 09:40:34 +01005930 ly_vlog_hide(1);
Radek Krejci48464ed2016-03-17 15:44:09 +01005931 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01005932 ly_vlog_hide(0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005933 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005934 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02005935 if (ly_log_level >= LY_LLERR) {
5936 path = strdup(ly_errpath());
5937 msg = strdup(ly_errmsg());
5938 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
5939 free(path);
5940 free(msg);
5941 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005942 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02005943 if (type == UNRES_LIST_UNIQ) {
5944 /* free the allocated structure */
5945 free(item);
5946 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005947 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02005948 } else {
5949 /* erase info about validation errors */
5950 ly_errno = LY_SUCCESS;
5951 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005952 }
5953
Radek Krejci48464ed2016-03-17 15:44:09 +01005954 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02005955
Michal Vasko88c29542015-11-27 14:57:53 +01005956 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02005957 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01005958 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005959 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
5960 lyxml_unlink_elem(mod->ctx, yin, 1);
5961 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
5962 }
Michal Vasko88c29542015-11-27 14:57:53 +01005963 }
5964
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005965 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01005966 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
5967 if (!unres->item) {
5968 LOGMEM;
5969 return -1;
5970 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005971 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01005972 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
5973 if (!unres->type) {
5974 LOGMEM;
5975 return -1;
5976 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005977 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01005978 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
5979 if (!unres->str_snode) {
5980 LOGMEM;
5981 return -1;
5982 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005983 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01005984 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
5985 if (!unres->module) {
5986 LOGMEM;
5987 return -1;
5988 }
5989 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005990
Michal Vasko3767fb22016-07-21 12:10:57 +02005991 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005992}
5993
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005994/**
Michal Vaskobb211122015-08-19 14:03:11 +02005995 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005996 *
5997 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005998 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005999 * @param[in] item Old item to be resolved.
6000 * @param[in] type Type of the old unresolved item.
6001 * @param[in] new_item New item to use in the duplicate.
6002 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006003 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006004 */
Michal Vaskodad19402015-08-06 09:51:53 +02006005int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006006unres_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 +02006007{
6008 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006009 struct unres_list_uniq aux_uniq;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006010
Michal Vaskocf024702015-10-08 15:01:42 +02006011 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006012
Radek Krejcid09d1a52016-08-11 14:05:45 +02006013 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6014 if (type == UNRES_LIST_UNIQ) {
6015 aux_uniq.list = item;
6016 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6017 item = &aux_uniq;
6018 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006019 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006020
6021 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006022 if (type == UNRES_LIST_UNIQ) {
6023 free(new_item);
6024 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006025 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006026 }
6027
Radek Krejcic79c6b12016-07-26 15:11:49 +02006028 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcid09d1a52016-08-11 14:05:45 +02006029 (type == UNRES_IFFEAT) || (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006030 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006031 LOGINT;
6032 return -1;
6033 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006034 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006035 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006036 LOGINT;
6037 return -1;
6038 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006039 }
Michal Vaskodad19402015-08-06 09:51:53 +02006040
6041 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006042}
6043
Michal Vaskof02e3742015-08-05 16:27:02 +02006044/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006045int
Michal Vasko878e38d2016-09-05 12:17:53 +02006046unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006047{
Michal Vasko878e38d2016-09-05 12:17:53 +02006048 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006049 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006050
Michal Vasko878e38d2016-09-05 12:17:53 +02006051 if (start_on_backwards > 0) {
6052 i = start_on_backwards;
6053 } else {
6054 i = unres->count - 1;
6055 }
6056 for (; i > -1; i--) {
6057 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006058 continue;
6059 }
6060 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006061 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006062 break;
6063 }
6064 } else {
6065 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6066 aux_uniq2 = (struct unres_list_uniq *)item;
6067 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006068 break;
6069 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006070 }
6071 }
6072
Michal Vasko878e38d2016-09-05 12:17:53 +02006073 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006074}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006075
Michal Vaskoede9c472016-06-07 09:38:15 +02006076static void
6077unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6078{
6079 struct lyxml_elem *yin;
6080 struct yang_type *yang;
6081
6082 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006083 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006084 case UNRES_TYPE_DER:
6085 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6086 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6087 yang =(struct yang_type *)yin;
6088 yang->type->base = yang->base;
6089 lydict_remove(ctx, yang->name);
6090 free(yang);
6091 } else {
6092 lyxml_free(ctx, yin);
6093 }
6094 break;
6095 case UNRES_IDENT:
6096 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006097 case UNRES_TYPE_DFLT:
6098 case UNRES_CHOICE_DFLT:
6099 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006100 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6101 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006102 case UNRES_LIST_UNIQ:
6103 free(unres->item[i]);
6104 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006105 default:
6106 break;
6107 }
6108 unres->type[i] = UNRES_RESOLVED;
6109}
6110
Michal Vasko88c29542015-11-27 14:57:53 +01006111void
Radek Krejcic071c542016-01-27 14:57:51 +01006112unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006113{
6114 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006115 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006116
Radek Krejcic071c542016-01-27 14:57:51 +01006117 if (!unres || !(*unres)) {
6118 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006119 }
6120
Radek Krejcic071c542016-01-27 14:57:51 +01006121 assert(module || (*unres)->count == 0);
6122
6123 for (i = 0; i < (*unres)->count; ++i) {
6124 if ((*unres)->module[i] != module) {
6125 if ((*unres)->type[i] != UNRES_RESOLVED) {
6126 unresolved++;
6127 }
6128 continue;
6129 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006130
6131 /* free heap memory for the specific item */
6132 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006133 }
6134
Michal Vaskoede9c472016-06-07 09:38:15 +02006135 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006136 if (!module || (!unresolved && !module->type)) {
6137 free((*unres)->item);
6138 free((*unres)->type);
6139 free((*unres)->str_snode);
6140 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006141 free((*unres));
6142 (*unres) = NULL;
6143 }
Michal Vasko88c29542015-11-27 14:57:53 +01006144}
6145
Michal Vasko8bcdf292015-08-19 14:04:43 +02006146/**
6147 * @brief Resolve a single unres data item. Logs directly.
6148 *
Michal Vaskocf024702015-10-08 15:01:42 +02006149 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006150 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006151 *
6152 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6153 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006154int
Radek Krejci48464ed2016-03-17 15:44:09 +01006155resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006156{
6157 uint32_t i;
Michal Vasko0491ab32015-08-19 14:28:29 +02006158 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006159 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006160 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006161 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006162 struct unres_data matches;
6163
6164 memset(&matches, 0, sizeof matches);
Michal Vasko83a6c462015-10-08 16:43:53 +02006165 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006166 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006167
Michal Vaskocf024702015-10-08 15:01:42 +02006168 switch (type) {
6169 case UNRES_LEAFREF:
6170 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vasko2471e7f2016-04-11 11:00:15 +02006171 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
6172 if (resolve_path_arg_data(node, sleaf->type.info.lref.path, &matches) == -1) {
6173 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006174 }
6175
6176 /* check that value matches */
6177 for (i = 0; i < matches.count; ++i) {
Radek Krejci749190d2016-02-18 16:26:25 +01006178 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Michal Vaskocf024702015-10-08 15:01:42 +02006179 leaf->value.leafref = matches.node[i];
Michal Vasko8bcdf292015-08-19 14:04:43 +02006180 break;
6181 }
6182 }
6183
Michal Vaskocf024702015-10-08 15:01:42 +02006184 free(matches.node);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006185
Michal Vaskocf024702015-10-08 15:01:42 +02006186 if (!leaf->value.leafref) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006187 /* reference not found */
Michal Vasko9925e282016-09-02 12:45:14 +02006188 if (sleaf->type.info.lref.req > -1) {
6189 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, sleaf->type.info.lref.path, leaf->value_str);
6190 return EXIT_FAILURE;
6191 } else {
6192 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6193 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02006194 }
Michal Vaskocf024702015-10-08 15:01:42 +02006195 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006196
Michal Vaskocf024702015-10-08 15:01:42 +02006197 case UNRES_INSTID:
Michal Vasko976a5f22016-05-18 13:28:42 +02006198 assert((sleaf->type.base == LY_TYPE_INST) || (sleaf->type.base == LY_TYPE_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006199 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006200 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006201 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006202 if (ly_errno) {
6203 return -1;
6204 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006205 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006206 return EXIT_FAILURE;
6207 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006208 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006209 }
6210 }
Michal Vaskocf024702015-10-08 15:01:42 +02006211 break;
6212
6213 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006214 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006215 return rc;
6216 }
6217 break;
6218
Michal Vaskobf19d252015-10-08 15:39:17 +02006219 case UNRES_MUST:
Radek Krejci48464ed2016-03-17 15:44:09 +01006220 if ((rc = resolve_must(node))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006221 return rc;
6222 }
6223 break;
6224
Michal Vaskoc4280842016-04-19 16:10:42 +02006225 case UNRES_EMPTYCONT:
6226 do {
6227 parent = node->parent;
6228 lyd_free(node);
6229 node = parent;
6230 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6231 && !((struct lys_node_container *)node->schema)->presence);
6232 break;
6233
Michal Vaskocf024702015-10-08 15:01:42 +02006234 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006235 LOGINT;
6236 return -1;
6237 }
6238
6239 return EXIT_SUCCESS;
6240}
6241
6242/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006243 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006244 *
6245 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006246 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006247 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006248 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006249 */
6250int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006251unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006252{
Radek Krejci03b71f72016-03-16 11:10:09 +01006253 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006254 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
6255 || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006256
Radek Krejci03b71f72016-03-16 11:10:09 +01006257 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006258 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6259 if (!unres->node) {
6260 LOGMEM;
6261 return -1;
6262 }
Michal Vaskocf024702015-10-08 15:01:42 +02006263 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006264 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6265 if (!unres->type) {
6266 LOGMEM;
6267 return -1;
6268 }
Michal Vaskocf024702015-10-08 15:01:42 +02006269 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006270
Radek Krejci0b7704f2016-03-18 12:16:14 +01006271 if (type == UNRES_WHEN) {
6272 /* remove previous result */
6273 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006274 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006275
6276 return EXIT_SUCCESS;
6277}
6278
6279/**
6280 * @brief Resolve every unres data item in the structure. Logs directly.
6281 *
6282 * @param[in] unres Unres data structure to use.
Radek Krejci03b71f72016-03-16 11:10:09 +01006283 * @param[in,out] root Root node of the data tree. If not NULL, auto-delete is performed on false when condition. If
6284 * NULL and when condition is false the error is raised.
Radek Krejci0c0086a2016-03-24 15:20:28 +01006285 * @param[in] options Parer options
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006286 *
6287 * @return EXIT_SUCCESS on success, -1 on error.
6288 */
6289int
Radek Krejci0c0086a2016-03-24 15:20:28 +01006290resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006291{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006292 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006293 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006294 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006295 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006296
Radek Krejci03b71f72016-03-16 11:10:09 +01006297 assert(unres);
Radek Krejci8ee1b562016-03-31 10:58:31 +02006298 assert((root && (*root)) || (options & LYD_OPT_NOAUTODEL));
Radek Krejci03b71f72016-03-16 11:10:09 +01006299
6300 if (!unres->count) {
6301 return EXIT_SUCCESS;
6302 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006303
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006304 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006305 ly_vlog_hide(1);
6306
Radek Krejci0b7704f2016-03-18 12:16:14 +01006307 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006308 ly_errno = LY_SUCCESS;
6309 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006310 do {
6311 progress = 0;
6312 for(i = 0; i < unres->count; i++) {
6313 if (unres->type[i] != UNRES_WHEN) {
6314 continue;
6315 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006316 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006317 /* count when-stmt nodes in unres list */
6318 when_stmt++;
6319 }
6320
6321 /* resolve when condition only when all parent when conditions are already resolved */
6322 for (parent = unres->node[i]->parent;
6323 parent && LYD_WHEN_DONE(parent->when_status);
6324 parent = parent->parent) {
6325 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6326 /* the parent node was already unlinked, do not resolve this node,
6327 * it will be removed anyway, so just mark it as resolved
6328 */
6329 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6330 unres->type[i] = UNRES_RESOLVED;
6331 resolved++;
6332 break;
6333 }
6334 }
6335 if (parent) {
6336 continue;
6337 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006338
Radek Krejci48464ed2016-03-17 15:44:09 +01006339 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006340 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006341 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
6342 if (!root) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006343 /* false when condition */
6344 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006345 if (ly_log_level >= LY_LLERR) {
6346 path = strdup(ly_errpath());
6347 msg = strdup(ly_errmsg());
6348 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6349 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6350 free(path);
6351 free(msg);
6352 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006353 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006354 } /* follows else */
6355
Radek Krejci0c0086a2016-03-24 15:20:28 +01006356 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6357 /* if it has parent non-presence containers that would be empty, we should actually
6358 * remove the container
6359 */
6360 if (!(options & LYD_OPT_KEEPEMPTYCONT)) {
6361 for (parent = unres->node[i];
6362 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6363 parent = parent->parent) {
6364 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6365 /* presence container */
6366 break;
6367 }
6368 if (parent->next || parent->prev != parent) {
6369 /* non empty (the child we are in and we are going to remove is not the only child) */
6370 break;
6371 }
6372 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006373 unres->node[i] = parent;
6374 }
6375
Radek Krejci0b7704f2016-03-18 12:16:14 +01006376 /* auto-delete */
6377 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6378 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006379 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006380 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006381 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006382
Radek Krejci0b7704f2016-03-18 12:16:14 +01006383 lyd_unlink(unres->node[i]);
6384 unres->type[i] = UNRES_DELETE;
6385 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006386
6387 /* update the rest of unres items */
6388 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01006389 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01006390 continue;
6391 }
6392
6393 /* test if the node is in subtree to be deleted */
6394 for (parent = unres->node[j]; parent; parent = parent->parent) {
6395 if (parent == unres->node[i]) {
6396 /* yes, it is */
6397 unres->type[j] = UNRES_RESOLVED;
6398 resolved++;
6399 break;
6400 }
6401 }
6402 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006403 } else {
6404 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01006405 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006406 ly_errno = LY_SUCCESS;
6407 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006408 resolved++;
6409 progress = 1;
6410 } else if (rc == -1) {
6411 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02006412 /* print only this last error */
6413 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006414 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006415 } else {
6416 /* forward reference, erase ly_errno */
6417 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006418 }
6419 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006420 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006421 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01006422
Radek Krejci0b7704f2016-03-18 12:16:14 +01006423 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01006424 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006425 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006426 if (ly_log_level >= LY_LLERR) {
6427 path = strdup(ly_errpath());
6428 msg = strdup(ly_errmsg());
6429 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6430 free(path);
6431 free(msg);
6432 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006433 return -1;
6434 }
6435
6436 for (i = 0; del_items && i < unres->count; i++) {
6437 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
6438 if (unres->type[i] != UNRES_DELETE) {
6439 continue;
6440 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006441 if (!unres->node[i]) {
6442 unres->type[i] = UNRES_RESOLVED;
6443 del_items--;
6444 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006445 }
6446
6447 /* really remove the complete subtree */
6448 lyd_free(unres->node[i]);
6449 unres->type[i] = UNRES_RESOLVED;
6450 del_items--;
6451 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006452
6453 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006455 if (unres->type[i] == UNRES_RESOLVED) {
6456 continue;
6457 }
6458
Radek Krejci48464ed2016-03-17 15:44:09 +01006459 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006460 if (rc == 0) {
6461 unres->type[i] = UNRES_RESOLVED;
6462 resolved++;
6463 } else if (rc == -1) {
6464 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02006465 /* print only this last error */
6466 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006467 return -1;
6468 }
6469 }
6470
Radek Krejci010e54b2016-03-15 09:40:34 +01006471 ly_vlog_hide(0);
6472 if (resolved < unres->count) {
6473 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
6474 * all the validation errors
6475 */
6476 for (i = 0; i < unres->count; ++i) {
6477 if (unres->type[i] == UNRES_RESOLVED) {
6478 continue;
6479 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006480 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006481 }
6482 return -1;
6483 }
6484
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006485 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01006486 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006487 return EXIT_SUCCESS;
6488}