blob: 61f1fd67a3c1254d9ef9088cb6b0ee53a8d8627b [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"
Radek Krejcie534c132016-11-23 13:32:31 +010032#include "extensions.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020033
Michal Vaskod24dd012016-09-30 12:20:22 +020034int
35parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020036{
37 const char *ptr;
38 int minus = 0;
39 int64_t ret = 0;
Radek Krejcibf47a822016-11-04 10:06:08 +010040 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020041
42 ptr = *str_num;
43
44 if (ptr[0] == '-') {
45 minus = 1;
46 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010047 } else if (ptr[0] == '+') {
48 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020049 }
50
Michal Vaskod24dd012016-09-30 12:20:22 +020051 if (!isdigit(ptr[0])) {
52 /* there must be at least one */
53 return 1;
54 }
55
Michal Vasko4d1f0482016-09-19 14:35:06 +020056 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
57 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020058 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020059 }
60
61 if (ptr[0] == '.') {
62 if (ptr[1] == '.') {
63 /* it's the next interval */
64 break;
65 }
66 ++str_dig;
67 } else {
Radek Krejcibf47a822016-11-04 10:06:08 +010068 ret = ret * 10 + (ptr[0] - '0');
Michal Vasko4d1f0482016-09-19 14:35:06 +020069 if (str_dig > -1) {
70 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010071 if (ptr[0] == '0') {
72 /* possibly trailing zero */
73 trailing_zeros++;
74 } else {
75 trailing_zeros = 0;
76 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020077 }
78 ++str_exp;
79 }
80 }
Michal Vaskod24dd012016-09-30 12:20:22 +020081 if (str_dig == 0) {
82 /* no digits after '.' */
83 return 1;
84 } else if (str_dig == -1) {
85 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020086 str_dig = 0;
87 }
Radek Krejcibf47a822016-11-04 10:06:08 +010088 /* remove trailing zeros */
89 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +010090 str_dig -= trailing_zeros;
91 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +010092 ret = ret / dec_pow(trailing_zeros);
93 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020094
95 /* it's parsed, now adjust the number based on fraction-digits, if needed */
96 if (str_dig < dig) {
97 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020098 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020099 }
100 ret *= dec_pow(dig - str_dig);
101 }
102 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200103 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200104 }
105
106 if (minus) {
107 ret *= -1;
108 }
109 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200110 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200111
Michal Vaskod24dd012016-09-30 12:20:22 +0200112 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200113}
114
115/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200116 * @brief Parse an identifier.
117 *
118 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
119 * identifier = (ALPHA / "_")
120 * *(ALPHA / DIGIT / "_" / "-" / ".")
121 *
Michal Vaskobb211122015-08-19 14:03:11 +0200122 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200123 *
124 * @return Number of characters successfully parsed.
125 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200126int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200127parse_identifier(const char *id)
128{
129 int parsed = 0;
130
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100131 assert(id);
132
Radek Krejci6dc53a22015-08-17 13:27:59 +0200133 if (!isalpha(id[0]) && (id[0] != '_')) {
134 return -parsed;
135 }
136
137 ++parsed;
138 ++id;
139
140 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
141 ++parsed;
142 ++id;
143 }
144
145 return parsed;
146}
147
148/**
149 * @brief Parse a node-identifier.
150 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200151 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200152 *
Michal Vaskobb211122015-08-19 14:03:11 +0200153 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200154 * @param[out] mod_name Points to the module name, NULL if there is not any.
155 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200156 * @param[out] name Points to the node name.
157 * @param[out] nam_len Length of the node name.
158 *
159 * @return Number of characters successfully parsed,
160 * positive on success, negative on failure.
161 */
162static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200163parse_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 +0200164{
165 int parsed = 0, ret;
166
167 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200168 if (mod_name) {
169 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200170 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200171 if (mod_name_len) {
172 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200173 }
174 if (name) {
175 *name = NULL;
176 }
177 if (nam_len) {
178 *nam_len = 0;
179 }
180
181 if ((ret = parse_identifier(id)) < 1) {
182 return ret;
183 }
184
Michal Vasko723e50c2015-10-20 15:20:29 +0200185 if (mod_name) {
186 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200187 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200188 if (mod_name_len) {
189 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200190 }
191
192 parsed += ret;
193 id += ret;
194
195 /* there is prefix */
196 if (id[0] == ':') {
197 ++parsed;
198 ++id;
199
200 /* there isn't */
201 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200202 if (name && mod_name) {
203 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200204 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200205 if (mod_name) {
206 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200207 }
208
Michal Vasko723e50c2015-10-20 15:20:29 +0200209 if (nam_len && mod_name_len) {
210 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200211 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200212 if (mod_name_len) {
213 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200214 }
215
216 return parsed;
217 }
218
219 /* identifier (node name) */
220 if ((ret = parse_identifier(id)) < 1) {
221 return -parsed+ret;
222 }
223
224 if (name) {
225 *name = id;
226 }
227 if (nam_len) {
228 *nam_len = ret;
229 }
230
231 return parsed+ret;
232}
233
234/**
235 * @brief Parse a path-predicate (leafref).
236 *
237 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
238 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
239 *
Michal Vaskobb211122015-08-19 14:03:11 +0200240 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200241 * @param[out] prefix Points to the prefix, NULL if there is not any.
242 * @param[out] pref_len Length of the prefix, 0 if there is not any.
243 * @param[out] name Points to the node name.
244 * @param[out] nam_len Length of the node name.
245 * @param[out] path_key_expr Points to the path-key-expr.
246 * @param[out] pke_len Length of the path-key-expr.
247 * @param[out] has_predicate Flag to mark whether there is another predicate following.
248 *
249 * @return Number of characters successfully parsed,
250 * positive on success, negative on failure.
251 */
252static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200253parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
254 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200255{
256 const char *ptr;
257 int parsed = 0, ret;
258
259 assert(id);
260 if (prefix) {
261 *prefix = NULL;
262 }
263 if (pref_len) {
264 *pref_len = 0;
265 }
266 if (name) {
267 *name = NULL;
268 }
269 if (nam_len) {
270 *nam_len = 0;
271 }
272 if (path_key_expr) {
273 *path_key_expr = NULL;
274 }
275 if (pke_len) {
276 *pke_len = 0;
277 }
278 if (has_predicate) {
279 *has_predicate = 0;
280 }
281
282 if (id[0] != '[') {
283 return -parsed;
284 }
285
286 ++parsed;
287 ++id;
288
289 while (isspace(id[0])) {
290 ++parsed;
291 ++id;
292 }
293
294 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
295 return -parsed+ret;
296 }
297
298 parsed += ret;
299 id += ret;
300
301 while (isspace(id[0])) {
302 ++parsed;
303 ++id;
304 }
305
306 if (id[0] != '=') {
307 return -parsed;
308 }
309
310 ++parsed;
311 ++id;
312
313 while (isspace(id[0])) {
314 ++parsed;
315 ++id;
316 }
317
318 if ((ptr = strchr(id, ']')) == NULL) {
319 return -parsed;
320 }
321
322 --ptr;
323 while (isspace(ptr[0])) {
324 --ptr;
325 }
326 ++ptr;
327
328 ret = ptr-id;
329 if (path_key_expr) {
330 *path_key_expr = id;
331 }
332 if (pke_len) {
333 *pke_len = ret;
334 }
335
336 parsed += ret;
337 id += ret;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 assert(id[0] == ']');
345
346 if (id[1] == '[') {
347 *has_predicate = 1;
348 }
349
350 return parsed+1;
351}
352
353/**
354 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
355 * the ".." and the first node-identifier, other calls parse a single
356 * node-identifier each.
357 *
358 * path-key-expr = current-function-invocation *WSP "/" *WSP
359 * rel-path-keyexpr
360 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
361 * *(node-identifier *WSP "/" *WSP)
362 * node-identifier
363 *
Michal Vaskobb211122015-08-19 14:03:11 +0200364 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200365 * @param[out] prefix Points to the prefix, NULL if there is not any.
366 * @param[out] pref_len Length of the prefix, 0 if there is not any.
367 * @param[out] name Points to the node name.
368 * @param[out] nam_len Length of the node name.
369 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
370 * must not be changed between consecutive calls.
371 * @return Number of characters successfully parsed,
372 * positive on success, negative on failure.
373 */
374static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200375parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
376 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200377{
378 int parsed = 0, ret, par_times = 0;
379
380 assert(id);
381 assert(parent_times);
382 if (prefix) {
383 *prefix = NULL;
384 }
385 if (pref_len) {
386 *pref_len = 0;
387 }
388 if (name) {
389 *name = NULL;
390 }
391 if (nam_len) {
392 *nam_len = 0;
393 }
394
395 if (!*parent_times) {
396 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
397 if (strncmp(id, "current()", 9)) {
398 return -parsed;
399 }
400
401 parsed += 9;
402 id += 9;
403
404 while (isspace(id[0])) {
405 ++parsed;
406 ++id;
407 }
408
409 if (id[0] != '/') {
410 return -parsed;
411 }
412
413 ++parsed;
414 ++id;
415
416 while (isspace(id[0])) {
417 ++parsed;
418 ++id;
419 }
420
421 /* rel-path-keyexpr */
422 if (strncmp(id, "..", 2)) {
423 return -parsed;
424 }
425 ++par_times;
426
427 parsed += 2;
428 id += 2;
429
430 while (isspace(id[0])) {
431 ++parsed;
432 ++id;
433 }
434 }
435
436 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
437 *
438 * first parent reference with whitespaces already parsed
439 */
440 if (id[0] != '/') {
441 return -parsed;
442 }
443
444 ++parsed;
445 ++id;
446
447 while (isspace(id[0])) {
448 ++parsed;
449 ++id;
450 }
451
452 while (!strncmp(id, "..", 2) && !*parent_times) {
453 ++par_times;
454
455 parsed += 2;
456 id += 2;
457
458 while (isspace(id[0])) {
459 ++parsed;
460 ++id;
461 }
462
463 if (id[0] != '/') {
464 return -parsed;
465 }
466
467 ++parsed;
468 ++id;
469
470 while (isspace(id[0])) {
471 ++parsed;
472 ++id;
473 }
474 }
475
476 if (!*parent_times) {
477 *parent_times = par_times;
478 }
479
480 /* all parent references must be parsed at this point */
481 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
482 return -parsed+ret;
483 }
484
485 parsed += ret;
486 id += ret;
487
488 return parsed;
489}
490
491/**
492 * @brief Parse path-arg (leafref).
493 *
494 * path-arg = absolute-path / relative-path
495 * absolute-path = 1*("/" (node-identifier *path-predicate))
496 * relative-path = 1*(".." "/") descendant-path
497 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200498 * @param[in] mod Module of the context node to get correct prefix in case it is not explicitly specified
Michal Vaskobb211122015-08-19 14:03:11 +0200499 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200500 * @param[out] prefix Points to the prefix, NULL if there is not any.
501 * @param[out] pref_len Length of the prefix, 0 if there is not any.
502 * @param[out] name Points to the node name.
503 * @param[out] nam_len Length of the node name.
504 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
505 * must not be changed between consecutive calls. -1 if the
506 * path is relative.
507 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
508 *
509 * @return Number of characters successfully parsed,
510 * positive on success, negative on failure.
511 */
512static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200513parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
514 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200515{
516 int parsed = 0, ret, par_times = 0;
517
518 assert(id);
519 assert(parent_times);
520 if (prefix) {
521 *prefix = NULL;
522 }
523 if (pref_len) {
524 *pref_len = 0;
525 }
526 if (name) {
527 *name = NULL;
528 }
529 if (nam_len) {
530 *nam_len = 0;
531 }
532 if (has_predicate) {
533 *has_predicate = 0;
534 }
535
536 if (!*parent_times && !strncmp(id, "..", 2)) {
537 ++par_times;
538
539 parsed += 2;
540 id += 2;
541
542 while (!strncmp(id, "/..", 3)) {
543 ++par_times;
544
545 parsed += 3;
546 id += 3;
547 }
548 }
549
550 if (!*parent_times) {
551 if (par_times) {
552 *parent_times = par_times;
553 } else {
554 *parent_times = -1;
555 }
556 }
557
558 if (id[0] != '/') {
559 return -parsed;
560 }
561
562 /* skip '/' */
563 ++parsed;
564 ++id;
565
566 /* node-identifier ([prefix:]identifier) */
567 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
568 return -parsed-ret;
569 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200570 if (!(*prefix)) {
571 /* actually we always need prefix even it is not specified */
572 *prefix = lys_main_module(mod)->name;
573 *pref_len = strlen(*prefix);
574 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575
576 parsed += ret;
577 id += ret;
578
579 /* there is no predicate */
580 if ((id[0] == '/') || !id[0]) {
581 return parsed;
582 } else if (id[0] != '[') {
583 return -parsed;
584 }
585
586 if (has_predicate) {
587 *has_predicate = 1;
588 }
589
590 return parsed;
591}
592
593/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200594 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200595 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 *
597 * instance-identifier = 1*("/" (node-identifier *predicate))
598 *
Michal Vaskobb211122015-08-19 14:03:11 +0200599 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200600 * @param[out] model Points to the model name.
601 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602 * @param[out] name Points to the node name.
603 * @param[out] nam_len Length of the node name.
604 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
605 *
606 * @return Number of characters successfully parsed,
607 * positive on success, negative on failure.
608 */
609static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200610parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
611 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612{
613 int parsed = 0, ret;
614
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 if (has_predicate) {
616 *has_predicate = 0;
617 }
618
619 if (id[0] != '/') {
620 return -parsed;
621 }
622
623 ++parsed;
624 ++id;
625
Michal Vaskob2f40be2016-09-08 16:03:48 +0200626 if ((ret = parse_identifier(id)) < 1) {
627 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200628 }
629
Michal Vaskob2f40be2016-09-08 16:03:48 +0200630 *model = id;
631 *mod_len = ret;
632
Radek Krejci6dc53a22015-08-17 13:27:59 +0200633 parsed += ret;
634 id += ret;
635
Michal Vaskob2f40be2016-09-08 16:03:48 +0200636 if (id[0] != ':') {
637 return -parsed;
638 }
639
640 ++parsed;
641 ++id;
642
643 if ((ret = parse_identifier(id)) < 1) {
644 return ret;
645 }
646
647 *name = id;
648 *nam_len = ret;
649
650 parsed += ret;
651 id += ret;
652
Radek Krejci4967cb62016-09-14 16:40:28 +0200653 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200654 *has_predicate = 1;
655 }
656
657 return parsed;
658}
659
660/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200661 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200662 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200663 *
664 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
665 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
666 * ((DQUOTE string DQUOTE) /
667 * (SQUOTE string SQUOTE))
668 * pos = non-negative-integer-value
669 *
Michal Vaskobb211122015-08-19 14:03:11 +0200670 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200671 * @param[out] model Points to the model name.
672 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200673 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
674 * @param[out] nam_len Length of the node name.
675 * @param[out] value Value the node-identifier must have (string from the grammar),
676 * NULL if there is not any.
677 * @param[out] val_len Length of the value, 0 if there is not any.
678 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
679 *
680 * @return Number of characters successfully parsed,
681 * positive on success, negative on failure.
682 */
683static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200684parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
685 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686{
687 const char *ptr;
688 int parsed = 0, ret;
689 char quote;
690
691 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200692 if (model) {
693 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200694 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200695 if (mod_len) {
696 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200697 }
698 if (name) {
699 *name = NULL;
700 }
701 if (nam_len) {
702 *nam_len = 0;
703 }
704 if (value) {
705 *value = NULL;
706 }
707 if (val_len) {
708 *val_len = 0;
709 }
710 if (has_predicate) {
711 *has_predicate = 0;
712 }
713
714 if (id[0] != '[') {
715 return -parsed;
716 }
717
718 ++parsed;
719 ++id;
720
721 while (isspace(id[0])) {
722 ++parsed;
723 ++id;
724 }
725
726 /* pos */
727 if (isdigit(id[0])) {
728 if (name) {
729 *name = id;
730 }
731
732 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200733 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200734 }
735
736 while (isdigit(id[0])) {
737 ++parsed;
738 ++id;
739 }
740
741 if (nam_len) {
742 *nam_len = id-(*name);
743 }
744
Michal Vaskof2f28a12016-09-09 12:43:06 +0200745 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200746 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200747 if (id[0] == '.') {
748 if (name) {
749 *name = id;
750 }
751 if (nam_len) {
752 *nam_len = 1;
753 }
754
755 ++parsed;
756 ++id;
757
758 } else {
759 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
760 return -parsed+ret;
761 } else if (model && !*model) {
762 return -parsed;
763 }
764
765 parsed += ret;
766 id += ret;
767 }
768
769 while (isspace(id[0])) {
770 ++parsed;
771 ++id;
772 }
773
774 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200775 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200776 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200777
Radek Krejci6dc53a22015-08-17 13:27:59 +0200778 ++parsed;
779 ++id;
780
Michal Vaskof2f28a12016-09-09 12:43:06 +0200781 while (isspace(id[0])) {
782 ++parsed;
783 ++id;
784 }
785
786 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
787 if ((id[0] == '\"') || (id[0] == '\'')) {
788 quote = id[0];
789
790 ++parsed;
791 ++id;
792
793 if ((ptr = strchr(id, quote)) == NULL) {
794 return -parsed;
795 }
796 ret = ptr-id;
797
798 if (value) {
799 *value = id;
800 }
801 if (val_len) {
802 *val_len = ret;
803 }
804
805 parsed += ret+1;
806 id += ret+1;
807 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200808 return -parsed;
809 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200810 }
811
812 while (isspace(id[0])) {
813 ++parsed;
814 ++id;
815 }
816
817 if (id[0] != ']') {
818 return -parsed;
819 }
820
821 ++parsed;
822 ++id;
823
824 if ((id[0] == '[') && has_predicate) {
825 *has_predicate = 1;
826 }
827
828 return parsed;
829}
830
831/**
832 * @brief Parse schema-nodeid.
833 *
834 * schema-nodeid = absolute-schema-nodeid /
835 * descendant-schema-nodeid
836 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200837 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200838 * node-identifier
839 * absolute-schema-nodeid
840 *
Michal Vaskobb211122015-08-19 14:03:11 +0200841 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200842 * @param[out] mod_name Points to the module name, NULL if there is not any.
843 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200844 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200845 * @param[out] nam_len Length of the node name.
846 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
847 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100848 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
849 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200850 *
851 * @return Number of characters successfully parsed,
852 * positive on success, negative on failure.
853 */
Michal Vasko22448d32016-03-16 13:17:29 +0100854int
Michal Vasko723e50c2015-10-20 15:20:29 +0200855parse_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 +0100856 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200857{
858 int parsed = 0, ret;
859
860 assert(id);
861 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200862 if (mod_name) {
863 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200864 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200865 if (mod_name_len) {
866 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200867 }
868 if (name) {
869 *name = NULL;
870 }
871 if (nam_len) {
872 *nam_len = 0;
873 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100874 if (has_predicate) {
875 *has_predicate = 0;
876 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200877
878 if (id[0] != '/') {
879 if (*is_relative != -1) {
880 return -parsed;
881 } else {
882 *is_relative = 1;
883 }
Michal Vasko48935352016-03-29 11:52:36 +0200884 if (!strncmp(id, "./", 2)) {
885 parsed += 2;
886 id += 2;
887 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200888 } else {
889 if (*is_relative == -1) {
890 *is_relative = 0;
891 }
892 ++parsed;
893 ++id;
894 }
895
Michal Vasko723e50c2015-10-20 15:20:29 +0200896 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200897 return -parsed+ret;
898 }
899
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100900 parsed += ret;
901 id += ret;
902
903 if ((id[0] == '[') && has_predicate) {
904 *has_predicate = 1;
905 }
906
907 return parsed;
908}
909
910/**
911 * @brief Parse schema predicate (special format internally used).
912 *
913 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko58c2aab2017-01-05 10:02:05 +0100914 * predicate-expr = "." / identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100915 * key-with-value = identifier *WSP "=" *WSP
916 * ((DQUOTE string DQUOTE) /
917 * (SQUOTE string SQUOTE))
918 *
919 * @param[in] id Identifier to use.
920 * @param[out] name Points to the list key name.
921 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100922 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100923 * @param[out] val_len Length of \p value.
924 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
925 */
Michal Vasko22448d32016-03-16 13:17:29 +0100926int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200927parse_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 +0100928 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100929{
930 const char *ptr;
931 int parsed = 0, ret;
932 char quote;
933
934 assert(id);
935 if (name) {
936 *name = NULL;
937 }
938 if (nam_len) {
939 *nam_len = 0;
940 }
941 if (value) {
942 *value = NULL;
943 }
944 if (val_len) {
945 *val_len = 0;
946 }
947 if (has_predicate) {
948 *has_predicate = 0;
949 }
950
951 if (id[0] != '[') {
952 return -parsed;
953 }
954
955 ++parsed;
956 ++id;
957
958 while (isspace(id[0])) {
959 ++parsed;
960 ++id;
961 }
962
Michal Vasko22448d32016-03-16 13:17:29 +0100963 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200964 if (id[0] == '.') {
965 ret = 1;
Michal Vasko58c2aab2017-01-05 10:02:05 +0100966 } else if (isdigit(id[0])) {
967 if (id[0] == '0') {
968 return -parsed;
969 }
970 ret = 1;
971 while (isdigit(id[ret])) {
972 ++ret;
973 }
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200974 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100975 return -parsed + ret;
976 }
977 if (name) {
978 *name = id;
979 }
980 if (nam_len) {
981 *nam_len = ret;
982 }
983
984 parsed += ret;
985 id += ret;
986
987 while (isspace(id[0])) {
988 ++parsed;
989 ++id;
990 }
991
992 /* there is value as well */
993 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +0100994 if (name && isdigit(**name)) {
995 return -parsed;
996 }
997
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100998 ++parsed;
999 ++id;
1000
1001 while (isspace(id[0])) {
1002 ++parsed;
1003 ++id;
1004 }
1005
1006 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1007 if ((id[0] == '\"') || (id[0] == '\'')) {
1008 quote = id[0];
1009
1010 ++parsed;
1011 ++id;
1012
1013 if ((ptr = strchr(id, quote)) == NULL) {
1014 return -parsed;
1015 }
1016 ret = ptr - id;
1017
1018 if (value) {
1019 *value = id;
1020 }
1021 if (val_len) {
1022 *val_len = ret;
1023 }
1024
1025 parsed += ret + 1;
1026 id += ret + 1;
1027 } else {
1028 return -parsed;
1029 }
1030
1031 while (isspace(id[0])) {
1032 ++parsed;
1033 ++id;
1034 }
1035 }
1036
1037 if (id[0] != ']') {
1038 return -parsed;
1039 }
1040
1041 ++parsed;
1042 ++id;
1043
1044 if ((id[0] == '[') && has_predicate) {
1045 *has_predicate = 1;
1046 }
1047
1048 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001049}
1050
1051/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001052 * @brief Resolve (find) a feature definition. Logs directly.
1053 *
1054 * @param[in] feat_name Feature name to resolve.
1055 * @param[in] len Length of \p feat_name.
1056 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001057 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1058 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001059 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001060 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001061 */
1062static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001063resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001064{
1065 char *str;
1066 const char *mod_name, *name;
1067 int mod_name_len, nam_len, i, j;
1068 const struct lys_module *module;
1069
Radek Krejci9ff0a922016-07-14 13:08:05 +02001070 assert(feature);
1071
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001072 /* check prefix */
1073 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1074 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1075 return -1;
1076 }
1077
1078 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1079 if (!module) {
1080 /* identity refers unknown data model */
1081 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1082 return -1;
1083 }
1084
Radek Krejci9ff0a922016-07-14 13:08:05 +02001085 if (module != node->module && module == lys_node_module(node)) {
1086 /* first, try to search directly in submodule where the feature was mentioned */
1087 for (j = 0; j < node->module->features_size; j++) {
1088 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1089 /* check status */
1090 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001091 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001092 return -1;
1093 }
1094 *feature = &node->module->features[j];
1095 return 0;
1096 }
1097 }
1098 }
1099
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001100 /* search in the identified module ... */
1101 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001102 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001103 /* check status */
1104 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001105 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001106 return -1;
1107 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001108 *feature = &module->features[j];
1109 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001110 }
1111 }
1112 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001113 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001114 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001115 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1116 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117 /* check status */
1118 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1119 module->inc[i].submodule->features[j].flags,
1120 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001121 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001122 return -1;
1123 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001124 *feature = &module->inc[i].submodule->features[j];
1125 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 }
1127 }
1128 }
1129
1130 /* not found */
1131 str = strndup(feat_name, len);
1132 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1133 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135}
1136
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137/*
1138 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001139 * - 1 if enabled
1140 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001141 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001142static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001143resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001144{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001145 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146
Radek Krejci9ff0a922016-07-14 13:08:05 +02001147 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001148 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001149 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001150 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001152
Radek Krejci69b8d922016-07-27 13:13:41 +02001153 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001154}
1155
1156static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001157resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001159 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001160 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001161
Radek Krejci9ff0a922016-07-14 13:08:05 +02001162 op = iff_getop(expr->expr, *index_e);
1163 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001164
Radek Krejci9ff0a922016-07-14 13:08:05 +02001165 switch (op) {
1166 case LYS_IFF_F:
1167 /* resolve feature */
1168 return resolve_feature_value(expr->features[(*index_f)++]);
1169 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001170 /* invert result */
1171 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001172 case LYS_IFF_AND:
1173 case LYS_IFF_OR:
1174 a = resolve_iffeature_recursive(expr, index_e, index_f);
1175 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001176 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001177 return a && b;
1178 } else { /* LYS_IFF_OR */
1179 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001180 }
1181 }
1182
Radek Krejciaf566332017-02-07 15:56:59 +01001183 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001184}
1185
1186int
1187resolve_iffeature(struct lys_iffeature *expr)
1188{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001189 int index_e = 0, index_f = 0;
1190
1191 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001192 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001193 }
Radek Krejciaf566332017-02-07 15:56:59 +01001194 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001195}
1196
1197struct iff_stack {
1198 int size;
1199 int index; /* first empty item */
1200 uint8_t *stack;
1201};
1202
1203static int
1204iff_stack_push(struct iff_stack *stack, uint8_t value)
1205{
1206 if (stack->index == stack->size) {
1207 stack->size += 4;
1208 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1209 if (!stack->stack) {
1210 LOGMEM;
1211 stack->size = 0;
1212 return EXIT_FAILURE;
1213 }
1214 }
1215
1216 stack->stack[stack->index++] = value;
1217 return EXIT_SUCCESS;
1218}
1219
1220static uint8_t
1221iff_stack_pop(struct iff_stack *stack)
1222{
1223 stack->index--;
1224 return stack->stack[stack->index];
1225}
1226
1227static void
1228iff_stack_clean(struct iff_stack *stack)
1229{
1230 stack->size = 0;
1231 free(stack->stack);
1232}
1233
1234static void
1235iff_setop(uint8_t *list, uint8_t op, int pos)
1236{
1237 uint8_t *item;
1238 uint8_t mask = 3;
1239
1240 assert(pos >= 0);
1241 assert(op <= 3); /* max 2 bits */
1242
1243 item = &list[pos / 4];
1244 mask = mask << 2 * (pos % 4);
1245 *item = (*item) & ~mask;
1246 *item = (*item) | (op << 2 * (pos % 4));
1247}
1248
1249uint8_t
1250iff_getop(uint8_t *list, int pos)
1251{
1252 uint8_t *item;
1253 uint8_t mask = 3, result;
1254
1255 assert(pos >= 0);
1256
1257 item = &list[pos / 4];
1258 result = (*item) & (mask << 2 * (pos % 4));
1259 return result >> 2 * (pos % 4);
1260}
1261
1262#define LYS_IFF_LP 0x04 /* ( */
1263#define LYS_IFF_RP 0x08 /* ) */
1264
Radek Krejcicbb473e2016-09-16 14:48:32 +02001265/* internal structure for passing data for UNRES_IFFEAT */
1266struct unres_iffeat_data {
1267 struct lys_node *node;
1268 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001269 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001270};
1271
Radek Krejci9ff0a922016-07-14 13:08:05 +02001272void
1273resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1274{
1275 unsigned int e = 0, f = 0, r = 0;
1276 uint8_t op;
1277
1278 assert(iffeat);
1279
1280 if (!iffeat->expr) {
1281 goto result;
1282 }
1283
1284 do {
1285 op = iff_getop(iffeat->expr, e++);
1286 switch (op) {
1287 case LYS_IFF_NOT:
1288 if (!r) {
1289 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001290 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001291 break;
1292 case LYS_IFF_AND:
1293 case LYS_IFF_OR:
1294 if (!r) {
1295 r += 2;
1296 } else {
1297 r += 1;
1298 }
1299 break;
1300 case LYS_IFF_F:
1301 f++;
1302 if (r) {
1303 r--;
1304 }
1305 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001306 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001307 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001308
Radek Krejci9ff0a922016-07-14 13:08:05 +02001309result:
1310 if (expr_size) {
1311 *expr_size = e;
1312 }
1313 if (feat_size) {
1314 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315 }
1316}
1317
1318int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001319resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001320 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001321{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001322 const char *c = value;
1323 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001324 int i, j, last_not, checkversion = 0;
1325 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326 uint8_t op;
1327 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001328 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001329
Radek Krejci9ff0a922016-07-14 13:08:05 +02001330 assert(c);
1331
1332 if (isspace(c[0])) {
1333 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1334 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001335 }
1336
Radek Krejci9ff0a922016-07-14 13:08:05 +02001337 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1338 for (i = j = last_not = 0; c[i]; i++) {
1339 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001340 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001341 j++;
1342 continue;
1343 } else if (c[i] == ')') {
1344 j--;
1345 continue;
1346 } else if (isspace(c[i])) {
1347 continue;
1348 }
1349
1350 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1351 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001352 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001353 return EXIT_FAILURE;
1354 } else if (!isspace(c[i + r])) {
1355 /* feature name starting with the not/and/or */
1356 last_not = 0;
1357 f_size++;
1358 } else if (c[i] == 'n') { /* not operation */
1359 if (last_not) {
1360 /* double not */
1361 expr_size = expr_size - 2;
1362 last_not = 0;
1363 } else {
1364 last_not = 1;
1365 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001366 } else { /* and, or */
1367 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001368 /* not a not operation */
1369 last_not = 0;
1370 }
1371 i += r;
1372 } else {
1373 f_size++;
1374 last_not = 0;
1375 }
1376 expr_size++;
1377
1378 while (!isspace(c[i])) {
1379 if (!c[i] || c[i] == ')') {
1380 i--;
1381 break;
1382 }
1383 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001384 }
1385 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001386 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001387 /* not matching count of ( and ) */
1388 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1389 return EXIT_FAILURE;
1390 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001391
Radek Krejci69b8d922016-07-27 13:13:41 +02001392 if (checkversion || expr_size > 1) {
1393 /* check that we have 1.1 module */
1394 if (node->module->version != 2) {
1395 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1396 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1397 return EXIT_FAILURE;
1398 }
1399 }
1400
Radek Krejci9ff0a922016-07-14 13:08:05 +02001401 /* allocate the memory */
1402 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001403 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001404 stack.size = expr_size;
1405 stack.stack = malloc(expr_size * sizeof *stack.stack);
1406 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1407 LOGMEM;
1408 goto error;
1409 }
1410 f_size--; expr_size--; /* used as indexes from now */
1411
1412 for (i--; i >= 0; i--) {
1413 if (c[i] == ')') {
1414 /* push it on stack */
1415 iff_stack_push(&stack, LYS_IFF_RP);
1416 continue;
1417 } else if (c[i] == '(') {
1418 /* pop from the stack into result all operators until ) */
1419 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1420 iff_setop(iffeat_expr->expr, op, expr_size--);
1421 }
1422 continue;
1423 } else if (isspace(c[i])) {
1424 continue;
1425 }
1426
1427 /* end operator or operand -> find beginning and get what is it */
1428 j = i + 1;
1429 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1430 i--;
1431 }
1432 i++; /* get back by one step */
1433
1434 if (!strncmp(&c[i], "not ", 4)) {
1435 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1436 /* double not */
1437 iff_stack_pop(&stack);
1438 } else {
1439 /* not has the highest priority, so do not pop from the stack
1440 * as in case of AND and OR */
1441 iff_stack_push(&stack, LYS_IFF_NOT);
1442 }
1443 } else if (!strncmp(&c[i], "and ", 4)) {
1444 /* as for OR - pop from the stack all operators with the same or higher
1445 * priority and store them to the result, then push the AND to the stack */
1446 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1447 op = iff_stack_pop(&stack);
1448 iff_setop(iffeat_expr->expr, op, expr_size--);
1449 }
1450 iff_stack_push(&stack, LYS_IFF_AND);
1451 } else if (!strncmp(&c[i], "or ", 3)) {
1452 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1453 op = iff_stack_pop(&stack);
1454 iff_setop(iffeat_expr->expr, op, expr_size--);
1455 }
1456 iff_stack_push(&stack, LYS_IFF_OR);
1457 } else {
1458 /* feature name, length is j - i */
1459
1460 /* add it to the result */
1461 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1462
1463 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001464 * forward referenced, we have to keep the feature name in auxiliary
1465 * structure passed into unres */
1466 iff_data = malloc(sizeof *iff_data);
1467 iff_data->node = node;
1468 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001469 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001470 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1471 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001472 f_size--;
1473
1474 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001475 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001476 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001477 }
1478 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001479 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001480 while (stack.index) {
1481 op = iff_stack_pop(&stack);
1482 iff_setop(iffeat_expr->expr, op, expr_size--);
1483 }
1484
1485 if (++expr_size || ++f_size) {
1486 /* not all expected operators and operands found */
1487 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1488 rc = EXIT_FAILURE;
1489 } else {
1490 rc = EXIT_SUCCESS;
1491 }
1492
1493error:
1494 /* cleanup */
1495 iff_stack_clean(&stack);
1496
1497 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001498}
1499
1500/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001501 * @brief Resolve (find) a data node based on a schema-nodeid.
1502 *
1503 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1504 * module).
1505 *
1506 */
1507struct lyd_node *
1508resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1509{
1510 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001511 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001512 const struct lys_node *schema = NULL;
1513
1514 assert(nodeid && start);
1515
1516 if (nodeid[0] == '/') {
1517 return NULL;
1518 }
1519
1520 str = p = strdup(nodeid);
1521 if (!str) {
1522 LOGMEM;
1523 return NULL;
1524 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001525
Michal Vasko3edeaf72016-02-11 13:17:43 +01001526 while (p) {
1527 token = p;
1528 p = strchr(p, '/');
1529 if (p) {
1530 *p = '\0';
1531 p++;
1532 }
1533
Radek Krejci5da4eb62016-04-08 14:45:51 +02001534 if (p) {
1535 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001536 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001537 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001538 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001539 result = NULL;
1540 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001541 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001542
Radek Krejci5da4eb62016-04-08 14:45:51 +02001543 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1544 continue;
1545 }
1546 } else {
1547 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001548 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001549 || !schema) {
1550 result = NULL;
1551 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001552 }
1553 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001554 LY_TREE_FOR(result ? result->child : start, iter) {
1555 if (iter->schema == schema) {
1556 /* move in data tree according to returned schema */
1557 result = iter;
1558 break;
1559 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001560 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001561 if (!iter) {
1562 /* instance not found */
1563 result = NULL;
1564 break;
1565 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001566 }
1567 free(str);
1568
1569 return result;
1570}
1571
Radek Krejcibdf92362016-04-08 14:43:34 +02001572/*
1573 * 0 - ok (done)
1574 * 1 - continue
1575 * 2 - break
1576 * -1 - error
1577 */
Radek Krejci1a9c3612017-04-24 14:49:43 +02001578int
Michal Vaskodc300b02017-04-07 14:09:20 +02001579schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001580 const char *mod_name, int mod_name_len, const struct lys_node **start_parent)
Radek Krejcibdf92362016-04-08 14:43:34 +02001581{
1582 const struct lys_module *prefix_mod;
1583
1584 /* module check */
1585 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1586 if (!prefix_mod) {
1587 return -1;
1588 }
1589 if (prefix_mod != lys_node_module(sibling)) {
1590 return 1;
1591 }
1592
Radek Krejcibdf92362016-04-08 14:43:34 +02001593 /* the result node? */
1594 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001595 return 0;
1596 }
1597
Michal Vaskodc300b02017-04-07 14:09:20 +02001598 /* move down the tree, if possible */
1599 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1600 return -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001601 }
Michal Vaskodc300b02017-04-07 14:09:20 +02001602 *start_parent = sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001603
1604 return 2;
1605}
1606
Radek Krejcidf46e222016-11-08 11:57:37 +01001607/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
Radek Krejcidf46e222016-11-08 11:57:37 +01001608 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001609int
1610resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001611 const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001612{
Michal Vaskobb520442017-05-23 10:55:18 +02001613 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001614 const struct lys_node *sibling, *start_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02001615 struct lys_node_augment *last_aug;
1616 int r, nam_len, mod_name_len = 0, is_relative = -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001617 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001618 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001619
1620 assert(nodeid && (start || module) && !(start && module) && ret);
1621
1622 id = nodeid;
1623
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001624 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 +01001625 return ((id - nodeid) - r) + 1;
1626 }
1627 id += r;
1628
1629 if ((is_relative && !start) || (!is_relative && !module)) {
1630 return -1;
1631 }
1632
1633 /* descendant-schema-nodeid */
1634 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001635 module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001636 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001637
Michal Vasko3edeaf72016-02-11 13:17:43 +01001638 /* absolute-schema-nodeid */
1639 } else {
1640 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001641 if (!start_mod) {
1642 return -1;
1643 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001644 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645 }
1646
1647 while (1) {
1648 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001649 last_aug = NULL;
1650
1651 if (start_parent) {
1652 if (mod_name && (strncmp(mod_name, lys_node_module(start_parent)->name, mod_name_len)
1653 || (mod_name_len != (signed) strlen(lys_node_module(start_parent)->name)))) {
1654 /* we are getting into another module (augment) */
1655 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1656 if (!aux_mod) {
1657 return -1;
1658 }
1659 } else {
1660 /* there is no mod_name or it matches the previous one, so why are we checking augments again?
1661 * because this module may be not implemented and it augments something in another module and
1662 * there is another augment augmenting that previous one */
1663 aux_mod = lys_node_module(start_parent);
1664 }
1665
1666 /* if the module is implemented, all the augments will be connected */
1667 if (!aux_mod->implemented) {
1668get_next_augment:
1669 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1670 }
1671 }
1672
1673 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001674 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001675 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001676 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001677 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001678 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001679 *ret = sibling;
1680 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001681 } else if (r == 1) {
1682 continue;
1683 } else if (r == 2) {
1684 break;
1685 } else {
1686 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001687 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001688 }
1689 }
1690
1691 /* no match */
1692 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001693 if (last_aug) {
1694 /* it still could be in another augment */
1695 goto get_next_augment;
1696 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001697 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001698 return EXIT_SUCCESS;
1699 }
1700
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001701 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 +01001702 return ((id - nodeid) - r) + 1;
1703 }
1704 id += r;
1705 }
1706
1707 /* cannot get here */
1708 LOGINT;
1709 return -1;
1710}
1711
Radek Krejcif3c71de2016-04-11 12:45:46 +02001712/* unique, refine,
1713 * >0 - unexpected char on position (ret - 1),
1714 * 0 - ok (but ret can still be NULL),
1715 * -1 - error,
1716 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001717int
1718resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001719 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720{
1721 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001722 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001723 int r, nam_len, mod_name_len, is_relative = -1;
1724 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001725 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001727 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001728 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001729
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001730 if (!start) {
1731 /* leaf not found */
1732 return 0;
1733 }
1734
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735 id = nodeid;
1736 module = start->module;
1737
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001738 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 +01001739 return ((id - nodeid) - r) + 1;
1740 }
1741 id += r;
1742
1743 if (!is_relative) {
1744 return -1;
1745 }
1746
Michal Vasko24476fa2017-03-08 12:33:48 +01001747 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001748 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001749 start_parent = lys_parent(start_parent);
1750 }
1751
Michal Vasko3edeaf72016-02-11 13:17:43 +01001752 while (1) {
1753 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001754 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001755 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001756 /* name match */
1757 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001758 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001759 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001760 if (!(sibling->nodetype & ret_nodetype)) {
1761 /* wrong node type, too bad */
1762 continue;
1763 }
1764 *ret = sibling;
1765 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001766 } else if (r == 1) {
1767 continue;
1768 } else if (r == 2) {
1769 break;
1770 } else {
1771 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001772 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 }
1774 }
1775
1776 /* no match */
1777 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001778 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001780 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1781 *ret = NULL;
1782 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001783 }
1784
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001785 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 +01001786 return ((id - nodeid) - r) + 1;
1787 }
1788 id += r;
1789 }
1790
1791 /* cannot get here */
1792 LOGINT;
1793 return -1;
1794}
1795
1796/* choice default */
1797int
1798resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1799{
1800 /* cannot actually be a path */
1801 if (strchr(nodeid, '/')) {
1802 return -1;
1803 }
1804
Michal Vaskodc300b02017-04-07 14:09:20 +02001805 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001806}
1807
1808/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1809static int
1810resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1811{
1812 const struct lys_module *module;
1813 const char *mod_prefix, *name;
1814 int i, mod_prefix_len, nam_len;
1815
1816 /* parse the identifier, it must be parsed on one call */
1817 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1818 return -i + 1;
1819 }
1820
1821 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1822 if (!module) {
1823 return -1;
1824 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01001825 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001826 start = module->data;
1827 }
1828
1829 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1830
1831 return EXIT_SUCCESS;
1832}
1833
1834int
1835resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1836 const struct lys_node **ret)
1837{
1838 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001839 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001840 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001841 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001842
1843 assert(nodeid && module && ret);
1844 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1845
1846 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01001847 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001848
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001849 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 +01001850 return ((id - nodeid) - r) + 1;
1851 }
1852 id += r;
1853
1854 if (is_relative) {
1855 return -1;
1856 }
1857
1858 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001859 if (!abs_start_mod) {
1860 return -1;
1861 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001862
1863 while (1) {
1864 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001865 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01001866 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1867 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001868 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001869 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001870 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001871 if (!(sibling->nodetype & ret_nodetype)) {
1872 /* wrong node type, too bad */
1873 continue;
1874 }
1875 *ret = sibling;
1876 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001877 } else if (r == 1) {
1878 continue;
1879 } else if (r == 2) {
1880 break;
1881 } else {
1882 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001883 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001884 }
1885 }
1886
1887 /* no match */
1888 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001889 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001890 return EXIT_SUCCESS;
1891 }
1892
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001893 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 +01001894 return ((id - nodeid) - r) + 1;
1895 }
1896 id += r;
1897 }
1898
1899 /* cannot get here */
1900 LOGINT;
1901 return -1;
1902}
1903
Michal Vaskoe733d682016-03-14 09:08:27 +01001904static int
Michal Vasko3547c532016-03-14 09:40:50 +01001905resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001906{
1907 const char *name;
1908 int nam_len, has_predicate, i;
1909
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001910 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1911 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001912 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001913 return -1;
1914 }
1915
1916 predicate += i;
1917 *parsed += i;
1918
Michal Vasko58c2aab2017-01-05 10:02:05 +01001919 if (!isdigit(name[0])) {
1920 for (i = 0; i < list->keys_size; ++i) {
1921 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1922 break;
1923 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001924 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001925
Michal Vasko58c2aab2017-01-05 10:02:05 +01001926 if (i == list->keys_size) {
1927 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1928 return -1;
1929 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001930 }
1931
1932 /* more predicates? */
1933 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001934 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001935 }
1936
1937 return 0;
1938}
1939
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001940/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001941const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001942resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001943{
Michal Vasko10728b52016-04-07 14:26:29 +02001944 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001945 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001946 const struct lys_node *sibling, *start_parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02001947 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001948 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001949 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001950
Michal Vasko3547c532016-03-14 09:40:50 +01001951 assert(nodeid && (ctx || start));
1952 if (!ctx) {
1953 ctx = start->module->ctx;
1954 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001955
1956 id = nodeid;
1957
Michal Vaskoe733d682016-03-14 09:08:27 +01001958 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 +01001959 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001960 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001961 }
1962 id += r;
1963
1964 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001965 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001966 start_parent = start;
1967 while (start_parent && (start_parent->nodetype == LYS_USES)) {
1968 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01001969 }
1970 module = start->module;
1971 } else {
1972 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001973 str = strndup(nodeid, (name + nam_len) - nodeid);
1974 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1975 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001976 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001977 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1978 LOGINT;
1979 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001980 }
1981
Michal Vasko971a3ca2016-04-01 13:09:29 +02001982 if (ly_buf_used && module_name[0]) {
1983 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1984 }
1985 ly_buf_used++;
1986
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001987 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001988 module_name[mod_name_len] = '\0';
1989 module = ly_ctx_get_module(ctx, module_name, NULL);
1990
1991 if (buf_backup) {
1992 /* return previous internal buffer content */
1993 strcpy(module_name, buf_backup);
1994 free(buf_backup);
1995 buf_backup = NULL;
1996 }
1997 ly_buf_used--;
1998
Michal Vasko3547c532016-03-14 09:40:50 +01001999 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002000 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2001 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2002 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002003 return NULL;
2004 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002005 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002006
2007 /* now it's as if there was no module name */
2008 mod_name = NULL;
2009 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002010 }
2011
Michal Vaskoe733d682016-03-14 09:08:27 +01002012 prev_mod = module;
2013
Michal Vasko3edeaf72016-02-11 13:17:43 +01002014 while (1) {
2015 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002016 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002017 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002018 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002019 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002020 /* module check */
2021 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002022 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002023 LOGINT;
2024 return NULL;
2025 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002026
2027 if (ly_buf_used && module_name[0]) {
2028 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2029 }
2030 ly_buf_used++;
2031
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002032 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002033 module_name[mod_name_len] = '\0';
2034 /* will also find an augment module */
2035 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002036
2037 if (buf_backup) {
2038 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002039 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002040 free(buf_backup);
2041 buf_backup = NULL;
2042 }
2043 ly_buf_used--;
2044
Michal Vasko3edeaf72016-02-11 13:17:43 +01002045 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002046 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2047 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2048 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002049 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002050 }
2051 } else {
2052 prefix_mod = prev_mod;
2053 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002054 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002055 continue;
2056 }
2057
Michal Vaskoe733d682016-03-14 09:08:27 +01002058 /* do we have some predicates on it? */
2059 if (has_predicate) {
2060 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002061 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2062 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2063 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2064 return NULL;
2065 }
2066 } else if (sibling->nodetype == LYS_LIST) {
2067 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2068 return NULL;
2069 }
2070 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002071 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002072 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002073 }
2074 id += r;
2075 }
2076
Michal Vasko3edeaf72016-02-11 13:17:43 +01002077 /* the result node? */
2078 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002079 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002080 }
2081
Michal Vaskodc300b02017-04-07 14:09:20 +02002082 /* move down the tree, if possible */
2083 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2084 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2085 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002086 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002087 start_parent = sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002088
2089 /* update prev mod */
Michal Vasko39608352017-05-11 10:37:10 +02002090 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002091 break;
2092 }
2093 }
2094
2095 /* no match */
2096 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002097 str = strndup(nodeid, (name + nam_len) - nodeid);
2098 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2099 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002100 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002101 }
2102
Michal Vaskoe733d682016-03-14 09:08:27 +01002103 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 +01002104 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002105 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002106 }
2107 id += r;
2108 }
2109
2110 /* cannot get here */
2111 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002112 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002113}
2114
Michal Vasko22448d32016-03-16 13:17:29 +01002115static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002116resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2117 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002118{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002119 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002120 int nam_len, val_len, has_predicate = 1, r;
2121 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002122 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002123
Radek Krejci61a86c62016-03-24 11:06:44 +01002124 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002125 assert(node->schema->nodetype == LYS_LIST);
2126
Michal Vasko53adfc72017-01-06 10:39:10 +01002127 /* is the predicate a number? */
2128 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2129 || !strncmp(name, ".", nam_len)) {
2130 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2131 return -1;
2132 }
2133
2134 if (isdigit(name[0])) {
2135 if (position == atoi(name)) {
2136 /* match */
2137 *parsed += r;
2138 return 0;
2139 } else {
2140 /* not a match */
2141 return 1;
2142 }
2143 }
2144
2145 if (!((struct lys_node_list *)node->schema)->keys_size) {
2146 /* no keys in schema - causes an error later */
2147 return 0;
2148 }
2149
Michal Vaskof29903d2016-04-18 13:13:10 +02002150 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002151 if (!key) {
2152 /* it is not a position, so we need a key for it to be a match */
2153 return 1;
2154 }
2155
2156 /* go through all the keys */
2157 i = 0;
2158 goto check_parsed_values;
2159
2160 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002161 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002162 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002163 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002164 }
2165
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002166 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2167 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002168 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002169 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002170 }
2171
Michal Vasko53adfc72017-01-06 10:39:10 +01002172check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002173 predicate += r;
2174 *parsed += r;
2175
Michal Vaskof29903d2016-04-18 13:13:10 +02002176 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002177 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002178 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002179 }
2180
Michal Vasko9ba34de2016-12-07 12:21:19 +01002181 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002182 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002183 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2184 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002185 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2186 } else {
2187 key_val = key->value_str;
2188 }
2189
Michal Vasko22448d32016-03-16 13:17:29 +01002190 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002191 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002192 return 1;
2193 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002194
2195 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002196 }
2197
2198 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002199 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002200 return -1;
2201 }
2202
2203 return 0;
2204}
2205
Radek Krejci45826012016-08-24 15:07:57 +02002206/**
2207 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2208 *
2209 * @param[in] nodeid Node data path to find
2210 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2211 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2212 * @param[out] parsed Number of characters processed in \p id
2213 * @return The closes parent (or the node itself) from the path
2214 */
Michal Vasko22448d32016-03-16 13:17:29 +01002215struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002216resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2217 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002218{
Michal Vasko10728b52016-04-07 14:26:29 +02002219 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002220 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002221 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002222 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002223 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002224 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002225 const struct lys_module *prefix_mod, *prev_mod;
2226 struct ly_ctx *ctx;
2227
2228 assert(nodeid && start && parsed);
2229
2230 ctx = start->schema->module->ctx;
2231 id = nodeid;
2232
2233 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 +01002234 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002235 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002236 return NULL;
2237 }
2238 id += r;
2239 /* add it to parsed only after the data node was actually found */
2240 last_parsed = r;
2241
2242 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002243 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002244 start = start->child;
2245 } else {
2246 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002247 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002248 }
2249
2250 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002251 list_instance_position = 0;
2252
Michal Vasko22448d32016-03-16 13:17:29 +01002253 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002254 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002255 if (lys_parent(sibling->schema)) {
2256 if (options & LYD_PATH_OPT_OUTPUT) {
2257 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002258 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002259 *parsed = -1;
2260 return NULL;
2261 }
2262 } else {
2263 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002264 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002265 *parsed = -1;
2266 return NULL;
2267 }
2268 }
2269 }
2270
Michal Vasko22448d32016-03-16 13:17:29 +01002271 /* name match */
2272 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2273
2274 /* module check */
2275 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002276 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002277 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002278 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002279 return NULL;
2280 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002281
2282 if (ly_buf_used && module_name[0]) {
2283 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2284 }
2285 ly_buf_used++;
2286
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002287 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002288 module_name[mod_name_len] = '\0';
2289 /* will also find an augment module */
2290 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002291
2292 if (buf_backup) {
2293 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002294 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002295 free(buf_backup);
2296 buf_backup = NULL;
2297 }
2298 ly_buf_used--;
2299
Michal Vasko22448d32016-03-16 13:17:29 +01002300 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002301 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2302 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2303 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002304 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002305 return NULL;
2306 }
2307 } else {
2308 prefix_mod = prev_mod;
2309 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002310 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002311 continue;
2312 }
2313
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002314 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002315 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002316 llist = (struct lyd_node_leaf_list *)sibling;
2317
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002318 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002319 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002320 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002321 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2322 *parsed = -1;
2323 return NULL;
2324 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002325 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2326 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2327 *parsed = -1;
2328 return NULL;
2329 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002330 } else {
2331 r = 0;
2332 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002333 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002334 }
2335 }
2336
Michal Vasko9ba34de2016-12-07 12:21:19 +01002337 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002338 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002339 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2340 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002341 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2342 } else {
2343 data_val = llist->value_str;
2344 }
2345
2346 if ((!llist_value && data_val && data_val[0])
2347 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002348 continue;
2349 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002350
Michal Vaskof0a50972016-10-19 11:33:55 +02002351 id += r;
2352 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002353 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002354
Radek Krejci45826012016-08-24 15:07:57 +02002355 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002356 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
Michal Vasko22448d32016-03-16 13:17:29 +01002357 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002358 /* none match */
2359 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002360 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002361
2362 ++list_instance_position;
2363 r = 0;
2364 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002365 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002366 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002367 return NULL;
2368 } else if (ret == 1) {
2369 /* this list instance does not match */
2370 continue;
2371 }
2372 id += r;
2373 last_parsed += r;
2374 }
2375
2376 *parsed += last_parsed;
2377
2378 /* the result node? */
2379 if (!id[0]) {
2380 return sibling;
2381 }
2382
2383 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002384 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002385 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002386 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002387 return NULL;
2388 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002389 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002390 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002391 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002392 break;
2393 }
2394 }
2395
2396 /* no match, return last match */
2397 if (!sibling) {
2398 return last_match;
2399 }
2400
2401 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 +01002402 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002403 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002404 return NULL;
2405 }
2406 id += r;
2407 last_parsed = r;
2408 }
2409
2410 /* cannot get here */
2411 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002412 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002413 return NULL;
2414}
2415
Michal Vasko3edeaf72016-02-11 13:17:43 +01002416/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002417 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002418 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002419 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002420 * @param[in] str_restr Restriction as a string.
2421 * @param[in] type Type of the restriction.
2422 * @param[out] ret Final interval structure that starts with
2423 * the interval of the initial type, continues with intervals
2424 * of any superior types derived from the initial one, and
2425 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002426 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002427 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002428 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002429int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002430resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002431{
2432 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002433 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002434 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002435 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002436 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002437 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002438 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002439
2440 switch (type->base) {
2441 case LY_TYPE_BINARY:
2442 kind = 0;
2443 local_umin = 0;
2444 local_umax = 18446744073709551615UL;
2445
2446 if (!str_restr && type->info.binary.length) {
2447 str_restr = type->info.binary.length->expr;
2448 }
2449 break;
2450 case LY_TYPE_DEC64:
2451 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002452 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2453 local_fmax = __INT64_C(9223372036854775807);
2454 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002455
2456 if (!str_restr && type->info.dec64.range) {
2457 str_restr = type->info.dec64.range->expr;
2458 }
2459 break;
2460 case LY_TYPE_INT8:
2461 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002462 local_smin = __INT64_C(-128);
2463 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002464
2465 if (!str_restr && type->info.num.range) {
2466 str_restr = type->info.num.range->expr;
2467 }
2468 break;
2469 case LY_TYPE_INT16:
2470 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002471 local_smin = __INT64_C(-32768);
2472 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002473
2474 if (!str_restr && type->info.num.range) {
2475 str_restr = type->info.num.range->expr;
2476 }
2477 break;
2478 case LY_TYPE_INT32:
2479 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002480 local_smin = __INT64_C(-2147483648);
2481 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002482
2483 if (!str_restr && type->info.num.range) {
2484 str_restr = type->info.num.range->expr;
2485 }
2486 break;
2487 case LY_TYPE_INT64:
2488 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002489 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2490 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002491
2492 if (!str_restr && type->info.num.range) {
2493 str_restr = type->info.num.range->expr;
2494 }
2495 break;
2496 case LY_TYPE_UINT8:
2497 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002498 local_umin = __UINT64_C(0);
2499 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002500
2501 if (!str_restr && type->info.num.range) {
2502 str_restr = type->info.num.range->expr;
2503 }
2504 break;
2505 case LY_TYPE_UINT16:
2506 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002507 local_umin = __UINT64_C(0);
2508 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002509
2510 if (!str_restr && type->info.num.range) {
2511 str_restr = type->info.num.range->expr;
2512 }
2513 break;
2514 case LY_TYPE_UINT32:
2515 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002516 local_umin = __UINT64_C(0);
2517 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002518
2519 if (!str_restr && type->info.num.range) {
2520 str_restr = type->info.num.range->expr;
2521 }
2522 break;
2523 case LY_TYPE_UINT64:
2524 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002525 local_umin = __UINT64_C(0);
2526 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002527
2528 if (!str_restr && type->info.num.range) {
2529 str_restr = type->info.num.range->expr;
2530 }
2531 break;
2532 case LY_TYPE_STRING:
2533 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002534 local_umin = __UINT64_C(0);
2535 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002536
2537 if (!str_restr && type->info.str.length) {
2538 str_restr = type->info.str.length->expr;
2539 }
2540 break;
2541 default:
2542 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002543 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002544 }
2545
2546 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002547 if (type->der) {
2548 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002549 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002550 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002551 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002552 assert(!intv || (intv->kind == kind));
2553 }
2554
2555 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002556 /* we do not have any restriction, return superior ones */
2557 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002558 return EXIT_SUCCESS;
2559 }
2560
2561 /* adjust local min and max */
2562 if (intv) {
2563 tmp_intv = intv;
2564
2565 if (kind == 0) {
2566 local_umin = tmp_intv->value.uval.min;
2567 } else if (kind == 1) {
2568 local_smin = tmp_intv->value.sval.min;
2569 } else if (kind == 2) {
2570 local_fmin = tmp_intv->value.fval.min;
2571 }
2572
2573 while (tmp_intv->next) {
2574 tmp_intv = tmp_intv->next;
2575 }
2576
2577 if (kind == 0) {
2578 local_umax = tmp_intv->value.uval.max;
2579 } else if (kind == 1) {
2580 local_smax = tmp_intv->value.sval.max;
2581 } else if (kind == 2) {
2582 local_fmax = tmp_intv->value.fval.max;
2583 }
2584 }
2585
2586 /* finally parse our restriction */
2587 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002588 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002589 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002590 if (!tmp_local_intv) {
2591 assert(!local_intv);
2592 local_intv = malloc(sizeof *local_intv);
2593 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002594 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002595 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002596 tmp_local_intv = tmp_local_intv->next;
2597 }
Michal Vasko253035f2015-12-17 16:58:13 +01002598 if (!tmp_local_intv) {
2599 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002600 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002601 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002602
2603 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002604 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002605 tmp_local_intv->next = NULL;
2606
2607 /* min */
2608 ptr = seg_ptr;
2609 while (isspace(ptr[0])) {
2610 ++ptr;
2611 }
2612 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2613 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002614 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002615 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002616 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002617 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002618 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2619 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2620 goto error;
2621 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002622 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002623 } else if (!strncmp(ptr, "min", 3)) {
2624 if (kind == 0) {
2625 tmp_local_intv->value.uval.min = local_umin;
2626 } else if (kind == 1) {
2627 tmp_local_intv->value.sval.min = local_smin;
2628 } else if (kind == 2) {
2629 tmp_local_intv->value.fval.min = local_fmin;
2630 }
2631
2632 ptr += 3;
2633 } else if (!strncmp(ptr, "max", 3)) {
2634 if (kind == 0) {
2635 tmp_local_intv->value.uval.min = local_umax;
2636 } else if (kind == 1) {
2637 tmp_local_intv->value.sval.min = local_smax;
2638 } else if (kind == 2) {
2639 tmp_local_intv->value.fval.min = local_fmax;
2640 }
2641
2642 ptr += 3;
2643 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002644 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002645 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002646 }
2647
2648 while (isspace(ptr[0])) {
2649 ptr++;
2650 }
2651
2652 /* no interval or interval */
2653 if ((ptr[0] == '|') || !ptr[0]) {
2654 if (kind == 0) {
2655 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2656 } else if (kind == 1) {
2657 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2658 } else if (kind == 2) {
2659 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2660 }
2661 } else if (!strncmp(ptr, "..", 2)) {
2662 /* skip ".." */
2663 ptr += 2;
2664 while (isspace(ptr[0])) {
2665 ++ptr;
2666 }
2667
2668 /* max */
2669 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2670 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002671 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002672 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002673 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002674 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002675 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2676 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2677 goto error;
2678 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002679 }
2680 } else if (!strncmp(ptr, "max", 3)) {
2681 if (kind == 0) {
2682 tmp_local_intv->value.uval.max = local_umax;
2683 } else if (kind == 1) {
2684 tmp_local_intv->value.sval.max = local_smax;
2685 } else if (kind == 2) {
2686 tmp_local_intv->value.fval.max = local_fmax;
2687 }
2688 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002689 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002690 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002691 }
2692 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002693 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002694 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002695 }
2696
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002697 /* check min and max in correct order*/
2698 if (kind == 0) {
2699 /* current segment */
2700 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2701 goto error;
2702 }
2703 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2704 goto error;
2705 }
2706 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002707 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002708 goto error;
2709 }
2710 } else if (kind == 1) {
2711 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2712 goto error;
2713 }
2714 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2715 goto error;
2716 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002717 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002718 goto error;
2719 }
2720 } else if (kind == 2) {
2721 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2722 goto error;
2723 }
2724 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2725 goto error;
2726 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002727 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002728 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002729 goto error;
2730 }
2731 }
2732
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002733 /* next segment (next OR) */
2734 seg_ptr = strchr(seg_ptr, '|');
2735 if (!seg_ptr) {
2736 break;
2737 }
2738 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002739 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002740 }
2741
2742 /* check local restrictions against superior ones */
2743 if (intv) {
2744 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002745 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002746
2747 while (tmp_local_intv && tmp_intv) {
2748 /* reuse local variables */
2749 if (kind == 0) {
2750 local_umin = tmp_local_intv->value.uval.min;
2751 local_umax = tmp_local_intv->value.uval.max;
2752
2753 /* it must be in this interval */
2754 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2755 /* this interval is covered, next one */
2756 if (local_umax <= tmp_intv->value.uval.max) {
2757 tmp_local_intv = tmp_local_intv->next;
2758 continue;
2759 /* ascending order of restrictions -> fail */
2760 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002761 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002762 }
2763 }
2764 } else if (kind == 1) {
2765 local_smin = tmp_local_intv->value.sval.min;
2766 local_smax = tmp_local_intv->value.sval.max;
2767
2768 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2769 if (local_smax <= tmp_intv->value.sval.max) {
2770 tmp_local_intv = tmp_local_intv->next;
2771 continue;
2772 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002773 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002774 }
2775 }
2776 } else if (kind == 2) {
2777 local_fmin = tmp_local_intv->value.fval.min;
2778 local_fmax = tmp_local_intv->value.fval.max;
2779
Michal Vasko4d1f0482016-09-19 14:35:06 +02002780 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002781 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002782 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002783 tmp_local_intv = tmp_local_intv->next;
2784 continue;
2785 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002786 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002787 }
2788 }
2789 }
2790
2791 tmp_intv = tmp_intv->next;
2792 }
2793
2794 /* some interval left uncovered -> fail */
2795 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002796 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002797 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002798 }
2799
Michal Vaskoaeb51802016-04-11 10:58:47 +02002800 /* append the local intervals to all the intervals of the superior types, return it all */
2801 if (intv) {
2802 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2803 tmp_intv->next = local_intv;
2804 } else {
2805 intv = local_intv;
2806 }
2807 *ret = intv;
2808
2809 return EXIT_SUCCESS;
2810
2811error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002812 while (intv) {
2813 tmp_intv = intv->next;
2814 free(intv);
2815 intv = tmp_intv;
2816 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002817 while (local_intv) {
2818 tmp_local_intv = local_intv->next;
2819 free(local_intv);
2820 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002821 }
2822
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002824}
2825
Michal Vasko730dfdf2015-08-11 14:48:05 +02002826/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002827 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2828 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002829 *
2830 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002831 * @param[in] mod_name Typedef name module name.
2832 * @param[in] module Main module.
2833 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002834 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002835 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002836 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002837 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002838int
Michal Vasko1e62a092015-12-01 12:27:20 +01002839resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2840 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002841{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002842 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002843 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 int tpdf_size;
2845
Michal Vasko1dca6882015-10-22 14:29:42 +02002846 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002847 /* no prefix, try built-in types */
2848 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002849 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002850 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002851 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002852 }
2853 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002854 }
2855 }
2856 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002857 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002858 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002859 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002860 }
2861 }
2862
Michal Vasko1dca6882015-10-22 14:29:42 +02002863 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002864 /* search in local typedefs */
2865 while (parent) {
2866 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002867 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002868 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2869 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 break;
2871
Radek Krejci76512572015-08-04 09:47:08 +02002872 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002873 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2874 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002875 break;
2876
Radek Krejci76512572015-08-04 09:47:08 +02002877 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002878 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2879 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002880 break;
2881
Radek Krejci76512572015-08-04 09:47:08 +02002882 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002883 case LYS_ACTION:
2884 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2885 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002886 break;
2887
Radek Krejci76512572015-08-04 09:47:08 +02002888 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002889 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2890 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002891 break;
2892
Radek Krejci76512572015-08-04 09:47:08 +02002893 case LYS_INPUT:
2894 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002895 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2896 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002897 break;
2898
2899 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002900 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002901 continue;
2902 }
2903
2904 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002905 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002906 match = &tpdf[i];
2907 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002908 }
2909 }
2910
Michal Vaskodcf98e62016-05-05 17:53:53 +02002911 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002912 }
Radek Krejcic071c542016-01-27 14:57:51 +01002913 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002914 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002915 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002916 if (!module) {
2917 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002918 }
2919 }
2920
2921 /* search in top level typedefs */
2922 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002923 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002924 match = &module->tpdf[i];
2925 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926 }
2927 }
2928
2929 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002930 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002932 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 +02002933 match = &module->inc[i].submodule->tpdf[j];
2934 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 }
2936 }
2937 }
2938
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002939 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002940
2941check_leafref:
2942 if (ret) {
2943 *ret = match;
2944 }
2945 if (match->type.base == LY_TYPE_LEAFREF) {
2946 while (!match->type.info.lref.path) {
2947 match = match->type.der;
2948 assert(match);
2949 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002950 }
2951 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002952}
2953
Michal Vasko1dca6882015-10-22 14:29:42 +02002954/**
2955 * @brief Check the default \p value of the \p type. Logs directly.
2956 *
2957 * @param[in] type Type definition to use.
2958 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002959 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002960 *
2961 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2962 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01002964check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002965{
Radek Krejcibad2f172016-08-02 11:04:15 +02002966 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002967 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002968 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02002969 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01002970 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002971
Radek Krejci51673202016-11-01 17:00:32 +01002972 assert(value);
2973
Radek Krejcic13db382016-08-16 10:52:42 +02002974 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002975 /* the type was not resolved yet, nothing to do for now */
2976 return EXIT_FAILURE;
Radek Krejci9e6af732017-04-27 14:40:25 +02002977 } else if (!tpdf && !lys_main_module(module)->implemented) {
2978 /* do not check defaults in not implemented module's data */
2979 return EXIT_SUCCESS;
2980 } else if (tpdf && !lys_main_module(module)->implemented && type->base == LY_TYPE_IDENT) {
2981 /* identityrefs are checked when instantiated in data instead of typedef,
2982 * but in typedef the value has to be modified to include the prefix */
2983 if (*value) {
2984 if (strchr(*value, ':')) {
2985 dflt = transform_schema2json(module, *value);
2986 } else {
2987 /* default prefix of the module where the typedef is defined */
2988 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
2989 dflt = lydict_insert_zc(module->ctx, s);
2990 }
2991 lydict_remove(module->ctx, *value);
2992 *value = dflt;
2993 }
2994 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01002995 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
2996 /* leafref in typedef cannot be checked */
2997 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002998 }
2999
Radek Krejci51673202016-11-01 17:00:32 +01003000 dflt = *value;
3001 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003002 /* we do not have a new default value, so is there any to check even, in some base type? */
3003 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3004 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003005 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003006 break;
3007 }
3008 }
3009
Radek Krejci51673202016-11-01 17:00:32 +01003010 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003011 /* no default value, nothing to check, all is well */
3012 return EXIT_SUCCESS;
3013 }
3014
3015 /* 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)? */
3016 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003017 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003018 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3019 return EXIT_SUCCESS;
3020 } else {
3021 /* check the default value from typedef, but use also the typedef's module
3022 * due to possible searching in imported modules which is expected in
3023 * typedef's module instead of module where the typedef is used */
3024 module = base_tpdf->module;
3025 }
3026 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003027 case LY_TYPE_INST:
3028 case LY_TYPE_LEAFREF:
3029 case LY_TYPE_BOOL:
3030 case LY_TYPE_EMPTY:
3031 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3032 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003033 case LY_TYPE_BITS:
3034 /* the default value must match the restricted list of values, if the type was restricted */
3035 if (type->info.bits.count) {
3036 break;
3037 }
3038 return EXIT_SUCCESS;
3039 case LY_TYPE_ENUM:
3040 /* the default value must match the restricted list of values, if the type was restricted */
3041 if (type->info.enums.count) {
3042 break;
3043 }
3044 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003045 case LY_TYPE_DEC64:
3046 if (type->info.dec64.range) {
3047 break;
3048 }
3049 return EXIT_SUCCESS;
3050 case LY_TYPE_BINARY:
3051 if (type->info.binary.length) {
3052 break;
3053 }
3054 return EXIT_SUCCESS;
3055 case LY_TYPE_INT8:
3056 case LY_TYPE_INT16:
3057 case LY_TYPE_INT32:
3058 case LY_TYPE_INT64:
3059 case LY_TYPE_UINT8:
3060 case LY_TYPE_UINT16:
3061 case LY_TYPE_UINT32:
3062 case LY_TYPE_UINT64:
3063 if (type->info.num.range) {
3064 break;
3065 }
3066 return EXIT_SUCCESS;
3067 case LY_TYPE_STRING:
3068 if (type->info.str.length || type->info.str.patterns) {
3069 break;
3070 }
3071 return EXIT_SUCCESS;
3072 case LY_TYPE_UNION:
3073 /* way too much trouble learning whether we need to check the default again, so just do it */
3074 break;
3075 default:
3076 LOGINT;
3077 return -1;
3078 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003079 } else if (type->base == LY_TYPE_EMPTY) {
3080 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3081 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3082 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003083 }
3084
Michal Vasko1dca6882015-10-22 14:29:42 +02003085 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003086 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003087 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003088 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003089 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003090 if (!node.schema) {
3091 LOGMEM;
3092 return -1;
3093 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003094 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003095 if (!node.schema->name) {
3096 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003097 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003098 return -1;
3099 }
Michal Vasko56826402016-03-02 11:11:37 +01003100 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003101 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003102
Radek Krejci37b756f2016-01-18 10:15:03 +01003103 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003104 if (!type->info.lref.target) {
3105 ret = EXIT_FAILURE;
3106 goto finish;
3107 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003108 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003109 if (!ret) {
3110 /* adopt possibly changed default value to its canonical form */
3111 if (*value) {
3112 *value = dflt;
3113 }
3114 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003115 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003116 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, NULL, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003117 /* possible forward reference */
3118 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003119 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003120 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003121 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3122 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3123 /* we have refined bits/enums */
3124 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3125 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003126 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003127 }
3128 }
Radek Krejci51673202016-11-01 17:00:32 +01003129 } else {
3130 /* success - adopt canonical form from the node into the default value */
3131 if (dflt != node.value_str) {
3132 /* this can happen only if we have non-inherited default value,
3133 * inherited default values are already in canonical form */
3134 assert(dflt == *value);
3135 *value = node.value_str;
3136 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003137 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003138 }
3139
3140finish:
3141 if (node.value_type == LY_TYPE_BITS) {
3142 free(node.value.bit);
3143 }
3144 free((char *)node.schema->name);
3145 free(node.schema);
3146
3147 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148}
3149
Michal Vasko730dfdf2015-08-11 14:48:05 +02003150/**
3151 * @brief Check a key for mandatory attributes. Logs directly.
3152 *
3153 * @param[in] key The key to check.
3154 * @param[in] flags What flags to check.
3155 * @param[in] list The list of all the keys.
3156 * @param[in] index Index of the key in the key list.
3157 * @param[in] name The name of the keys.
3158 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003159 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003160 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003161 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003162static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003163check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003164{
Radek Krejciadb57612016-02-16 13:34:34 +01003165 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166 char *dup = NULL;
3167 int j;
3168
3169 /* existence */
3170 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003171 if (name[len] != '\0') {
3172 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003173 if (!dup) {
3174 LOGMEM;
3175 return -1;
3176 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003177 dup[len] = '\0';
3178 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003180 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003181 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003182 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003183 }
3184
3185 /* uniqueness */
3186 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003187 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003188 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003189 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003190 }
3191 }
3192
3193 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003194 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003195 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003196 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197 }
3198
3199 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003200 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003201 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003202 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
3204
3205 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003206 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003207 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
3210
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003211 /* key is not placed from augment */
3212 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003213 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003214 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003215 return -1;
3216 }
3217
Radek Krejci3f21ada2016-08-01 13:34:31 +02003218 /* key is not when/if-feature -conditional */
3219 j = 0;
3220 if (key->when || (key->iffeature_size && (j = 1))) {
3221 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003222 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003223 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003224 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003225 }
3226
Michal Vasko0b85aa82016-03-07 14:37:43 +01003227 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003228}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003229
3230/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003231 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003232 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003233 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003234 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003235 *
3236 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3237 */
3238int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003239resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240{
Radek Krejci581ce772015-11-10 17:22:40 +01003241 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003242 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243
Michal Vaskodc300b02017-04-07 14:09:20 +02003244 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003245 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003246 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003247 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003248 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003249 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003250 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003251 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003252 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003253 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003254 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003255 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003256 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003257 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003258 }
Radek Krejci581ce772015-11-10 17:22:40 +01003259 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003260 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003261 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003262 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003263 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003264 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265 }
3266
Radek Krejcicf509982015-12-15 09:22:44 +01003267 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003268 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3269 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003270 return -1;
3271 }
3272
Radek Krejcid09d1a52016-08-11 14:05:45 +02003273 /* check that all unique's targets are of the same config type */
3274 if (*trg_type) {
3275 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3276 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003277 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003278 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3279 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3280 return -1;
3281 }
3282 } else {
3283 /* first unique */
3284 if (leaf->flags & LYS_CONFIG_W) {
3285 *trg_type = 1;
3286 } else {
3287 *trg_type = 2;
3288 }
3289 }
3290
Radek Krejcica7efb72016-01-18 13:06:01 +01003291 /* set leaf's unique flag */
3292 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3293
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003294 return EXIT_SUCCESS;
3295
3296error:
3297
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003298 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299}
3300
Radek Krejci0c0086a2016-03-24 15:20:28 +01003301void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003302unres_data_del(struct unres_data *unres, uint32_t i)
3303{
3304 /* there are items after the one deleted */
3305 if (i+1 < unres->count) {
3306 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003307 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003308
3309 /* deleting the last item */
3310 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003311 free(unres->node);
3312 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003313 }
3314
3315 /* if there are no items after and it is not the last one, just move the counter */
3316 --unres->count;
3317}
3318
Michal Vasko0491ab32015-08-19 14:28:29 +02003319/**
3320 * @brief Resolve (find) a data node from a specific module. Does not log.
3321 *
3322 * @param[in] mod Module to search in.
3323 * @param[in] name Name of the data node.
3324 * @param[in] nam_len Length of the name.
3325 * @param[in] start Data node to start the search from.
3326 * @param[in,out] parents Resolved nodes. If there are some parents,
3327 * they are replaced (!!) with the resolvents.
3328 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003329 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003330 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003331static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003332resolve_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 +02003333{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003334 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003335 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003336 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003337
Michal Vasko23b61ec2015-08-19 11:19:50 +02003338 if (!parents->count) {
3339 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003340 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003341 if (!parents->node) {
3342 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003343 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003344 }
Michal Vaskocf024702015-10-08 15:01:42 +02003345 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003346 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003347 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003348 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003349 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003350 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351 continue;
3352 }
3353 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003354 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003355 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 && node->schema->name[nam_len] == '\0') {
3357 /* matching target */
3358 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003359 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003360 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003361 flag = 1;
3362 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003363 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003364 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003365 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3366 if (!parents->node) {
3367 return EXIT_FAILURE;
3368 }
Michal Vaskocf024702015-10-08 15:01:42 +02003369 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003370 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371 }
3372 }
3373 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003374
3375 if (!flag) {
3376 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003377 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003378 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003379 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003380 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 }
3382
Michal Vasko0491ab32015-08-19 14:28:29 +02003383 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003384}
3385
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003386/**
3387 * @brief Resolve (find) a data node. Does not log.
3388 *
Radek Krejci581ce772015-11-10 17:22:40 +01003389 * @param[in] mod_name Module name of the data node.
3390 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003391 * @param[in] name Name of the data node.
3392 * @param[in] nam_len Length of the name.
3393 * @param[in] start Data node to start the search from.
3394 * @param[in,out] parents Resolved nodes. If there are some parents,
3395 * they are replaced (!!) with the resolvents.
3396 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003397 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003398 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003399static int
Radek Krejci581ce772015-11-10 17:22:40 +01003400resolve_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 +02003401 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003402{
Michal Vasko1e62a092015-12-01 12:27:20 +01003403 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003404 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003405
Michal Vasko23b61ec2015-08-19 11:19:50 +02003406 assert(start);
3407
Michal Vasko31fc3672015-10-21 12:08:13 +02003408 if (mod_name) {
3409 /* we have mod_name, find appropriate module */
3410 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003411 if (!str) {
3412 LOGMEM;
3413 return -1;
3414 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003415 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3416 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003417 if (!mod) {
3418 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003419 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003420 }
3421 } else {
3422 /* no prefix, module is the same as of current node */
Michal Vasko39608352017-05-11 10:37:10 +02003423 mod = lyd_node_module(start);
Radek Krejcic5090c32015-08-12 09:46:19 +02003424 }
3425
3426 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427}
3428
Michal Vasko730dfdf2015-08-11 14:48:05 +02003429/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003430 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003431 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003432 *
Michal Vaskobb211122015-08-19 14:03:11 +02003433 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003434 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003435 * @param[in,out] node_match Nodes satisfying the restriction
3436 * without the predicate. Nodes not
3437 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003438 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003439 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003440 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003441 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003442static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003443resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003444 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003446 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003447 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003448 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003449 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3450 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003451 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003452 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003453
3454 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003455 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003456 if (!source_match.node) {
3457 LOGMEM;
3458 return -1;
3459 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003460 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003461 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003462 if (!dest_match.node) {
3463 LOGMEM;
3464 return -1;
3465 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003466
3467 do {
3468 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3469 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003470 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003471 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003472 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003474 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003475 pred += i;
3476
Michal Vasko23b61ec2015-08-19 11:19:50 +02003477 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003479 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003482 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003483 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484 i = 0;
3485 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486 }
3487
3488 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003489 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003490 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3492 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003493 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003494 rc = -1;
3495 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003496 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003497 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003499 dest_match.node[0] = dest_match.node[0]->parent;
3500 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003501 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003502 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003503 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 }
3505 }
3506 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003507 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003508 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003509 i = 0;
3510 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511 }
3512
3513 if (pke_len == pke_parsed) {
3514 break;
3515 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003516 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 +02003517 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003518 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003519 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003520 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003521 }
3522 pke_parsed += i;
3523 }
3524
3525 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003526 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003527 while (leaf_dst && leaf_dst->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003528 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3529 }
3530 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003531 while (leaf_src && leaf_src->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003532 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3533 }
Radek Krejci981a8ee2017-03-17 16:48:26 +01003534 if (!leaf_src || !leaf_dst) {
3535 /* not yet resolved leafrefs */
3536 return EXIT_FAILURE;
3537 }
Radek Krejcic7408e72017-03-17 10:43:51 +01003538 if ((leaf_src->value_type & LY_DATA_TYPE_MASK) != (leaf_dst->value_type & LY_DATA_TYPE_MASK)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003539 goto remove_leafref;
3540 }
3541
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003542 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003543 goto remove_leafref;
3544 }
3545
3546 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003547 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003548 continue;
3549
3550remove_leafref:
3551 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003552 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003553 }
3554 } while (has_predicate);
3555
Michal Vaskocf024702015-10-08 15:01:42 +02003556 free(source_match.node);
3557 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003558 if (parsed) {
3559 *parsed = parsed_loc;
3560 }
3561 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003562
3563error:
3564
3565 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003566 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003567 }
3568 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003569 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003570 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003571 if (parsed) {
3572 *parsed = -parsed_loc+i;
3573 }
3574 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003575}
3576
Michal Vasko730dfdf2015-08-11 14:48:05 +02003577/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003578 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003579 *
Michal Vaskocf024702015-10-08 15:01:42 +02003580 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003581 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003582 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003583 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003584 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003585 */
Michal Vasko184521f2015-09-24 13:14:26 +02003586static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003587resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588{
Radek Krejci71b795b2015-08-10 16:20:39 +02003589 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003590 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003591 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003592 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003593
Michal Vaskocf024702015-10-08 15:01:42 +02003594 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003595
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003596 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003597 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003598
3599 /* searching for nodeset */
3600 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003601 if ((i = parse_path_arg(node->schema->module, path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003602 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003603 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003604 goto error;
3605 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003606 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003607 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003608
Michal Vasko23b61ec2015-08-19 11:19:50 +02003609 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003610 if (parent_times > 0) {
3611 data = node;
3612 for (i = 1; i < parent_times; ++i) {
3613 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003614 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003615 } else if (!parent_times) {
3616 data = node->child;
3617 } else {
3618 /* absolute path */
3619 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003620 }
3621
Michal Vaskobfd98e62016-09-02 09:50:05 +02003622 /* we may still be parsing it and the pointer is not correct yet */
3623 if (data->prev) {
3624 while (data->prev->next) {
3625 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003626 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627 }
3628 }
3629
3630 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003631 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003632 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003633 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003634 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003635 goto error;
3636 }
3637
3638 if (has_predicate) {
3639 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003640 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003641 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3642 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003643 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003644 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645 continue;
3646 }
3647
3648 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003649 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003650 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003651 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003652 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003653 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003654 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003655 goto error;
3656 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003657 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003658 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003659
Michal Vasko23b61ec2015-08-19 11:19:50 +02003660 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003661 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662 goto error;
3663 }
3664 }
3665 } while (path[0] != '\0');
3666
Michal Vaskof02e3742015-08-05 16:27:02 +02003667 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003668
3669error:
3670
Michal Vaskocf024702015-10-08 15:01:42 +02003671 free(ret->node);
3672 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003673 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003674
Michal Vasko0491ab32015-08-19 14:28:29 +02003675 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003676}
3677
Michal Vaskoe27516a2016-10-10 17:55:31 +00003678static int
Michal Vasko1c007172017-03-10 10:20:44 +01003679resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003680{
3681 int dep1, dep2;
3682 const struct lys_node *node;
3683
3684 if (lys_parent(op_node)) {
3685 /* inner operation (notif/action) */
3686 if (abs_path) {
3687 return 1;
3688 } else {
3689 /* compare depth of both nodes */
3690 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3691 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3692 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3693 return 1;
3694 }
3695 }
3696 } else {
3697 /* top-level operation (notif/rpc) */
3698 if (op_node != first_node) {
3699 return 1;
3700 }
3701 }
3702
3703 return 0;
3704}
3705
Michal Vasko730dfdf2015-08-11 14:48:05 +02003706/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003707 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003708 *
Michal Vaskobb211122015-08-19 14:03:11 +02003709 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003710 * @param[in] context_node Predicate context node (where the predicate is placed).
3711 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003712 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003713 *
Michal Vasko184521f2015-09-24 13:14:26 +02003714 * @return 0 on forward reference, otherwise the number
3715 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003716 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003717 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003718static int
Michal Vasko1c007172017-03-10 10:20:44 +01003719resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3720 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003721{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003722 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003723 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003724 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003725 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3726 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003727
3728 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003730 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003731 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003732 return -parsed+i;
3733 }
3734 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003736
Michal Vasko58090902015-08-13 14:04:15 +02003737 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003738 if (sour_pref) {
3739 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3740 } else {
3741 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003742 }
Michal Vaskobb520442017-05-23 10:55:18 +02003743 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003744 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003745 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003746 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003747 }
3748
3749 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003750 dest_parent_times = 0;
3751 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003752 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3753 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003754 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 +02003755 return -parsed;
3756 }
3757 pke_parsed += i;
3758
Radek Krejciadb57612016-02-16 13:34:34 +01003759 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003760 /* path is supposed to be evaluated in data tree, so we have to skip
3761 * all schema nodes that cannot be instantiated in data tree */
3762 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003763 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003764 dst_node = lys_parent(dst_node));
3765
Michal Vasko1f76a282015-08-04 16:16:53 +02003766 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003767 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003768 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003769 }
3770 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003771 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003773 if (dest_pref) {
3774 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3775 } else {
3776 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003777 }
Michal Vaskobb520442017-05-23 10:55:18 +02003778 rc = lys_getnext_data(trg_mod, dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003779 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003780 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003781 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003782 }
3783
Michal Vaskoe27516a2016-10-10 17:55:31 +00003784 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003785 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003786 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003787 }
3788 first_iter = 0;
3789 }
3790
Michal Vasko1f76a282015-08-04 16:16:53 +02003791 if (pke_len == pke_parsed) {
3792 break;
3793 }
3794
Michal Vaskobb520442017-05-23 10:55:18 +02003795 if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vasko1f76a282015-08-04 16:16:53 +02003796 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003797 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003798 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003799 return -parsed;
3800 }
3801 pke_parsed += i;
3802 }
3803
3804 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003805 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003806 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003807 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003808 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003809 return -parsed;
3810 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003811 } while (has_predicate);
3812
3813 return parsed;
3814}
3815
Michal Vasko730dfdf2015-08-11 14:48:05 +02003816/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003817 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003818 *
Michal Vaskobb211122015-08-19 14:03:11 +02003819 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003820 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003821 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003822 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003823 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003824 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003825static int
Michal Vasko1c007172017-03-10 10:20:44 +01003826resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003827{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003828 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003829 struct lys_node_augment *last_aug;
3830 const struct lys_module *cur_mod;
Radek Krejci990af1f2016-11-09 13:53:36 +01003831 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003832 const char *id, *prefix, *name;
3833 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003834 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003835
Michal Vasko184521f2015-09-24 13:14:26 +02003836 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003837 parent_times = 0;
3838 id = path;
3839
Michal Vasko1c007172017-03-10 10:20:44 +01003840 /* find operation schema we are in */
3841 for (op_node = lys_parent(parent);
3842 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3843 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003844
Radek Krejci990af1f2016-11-09 13:53:36 +01003845 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003846 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003847 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko1c007172017-03-10 10:20:44 +01003848 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003849 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003850 }
3851 id += i;
3852
Michal Vaskobb520442017-05-23 10:55:18 +02003853 /* get the current module */
3854 cur_mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3855 if (!cur_mod) {
3856 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3857 return EXIT_FAILURE;
3858 }
3859 last_aug = NULL;
3860
Michal Vasko184521f2015-09-24 13:14:26 +02003861 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003862 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003863 /* use module data */
3864 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003865
Michal Vasko1f76a282015-08-04 16:16:53 +02003866 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003867 /* we are looking for the right parent */
3868 for (i = 0, node = parent; i < parent_times; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003869 /* path is supposed to be evaluated in data tree, so we have to skip
3870 * all schema nodes that cannot be instantiated in data tree */
3871 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003872 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003873 node = lys_parent(node));
3874
Michal Vasko1f76a282015-08-04 16:16:53 +02003875 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003876 if (i == parent_times - 1) {
3877 /* top-level */
3878 break;
3879 }
3880
3881 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003882 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003883 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003884 }
3885 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003886 } else {
3887 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003888 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003889 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003890 }
3891
Michal Vaskobb520442017-05-23 10:55:18 +02003892 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3893 * - useless to search for that in augments) */
3894 if (!cur_mod->implemented && node) {
3895get_next_augment:
3896 last_aug = lys_getnext_target_aug(last_aug, cur_mod, node);
3897 }
3898
3899 rc = lys_getnext_data(cur_mod, (last_aug ? (struct lys_node *)last_aug : node), name, nam_len, LYS_LIST
3900 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003901 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003902 if (last_aug) {
3903 goto get_next_augment;
3904 }
Michal Vasko1c007172017-03-10 10:20:44 +01003905 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003906 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003907 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003908
Michal Vaskoe27516a2016-10-10 17:55:31 +00003909 if (first_iter) {
3910 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003911 if (op_node && parent_times &&
3912 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003913 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003914 }
3915 first_iter = 0;
3916 }
3917
Michal Vasko1f76a282015-08-04 16:16:53 +02003918 if (has_predicate) {
3919 /* we have predicate, so the current result must be list */
3920 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003921 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003922 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003923 }
3924
Michal Vasko1c007172017-03-10 10:20:44 +01003925 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003926 if (!i) {
3927 return EXIT_FAILURE;
3928 } else if (i < 0) {
3929 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003930 }
3931 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003932 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003933 }
3934 } while (id[0]);
3935
Michal Vaskoca917682016-07-25 11:00:37 +02003936 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003937 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003938 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003939 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003940 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003941 }
3942
Radek Krejcicf509982015-12-15 09:22:44 +01003943 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003944 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003945 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003946 return -1;
3947 }
3948
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003949 if (ret) {
3950 *ret = node;
3951 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003952
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003953 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003954}
3955
Michal Vasko730dfdf2015-08-11 14:48:05 +02003956/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003957 * @brief Resolve instance-identifier predicate in JSON data format.
3958 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003959 *
Michal Vaskobb211122015-08-19 14:03:11 +02003960 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003961 * @param[in,out] node_match Nodes matching the restriction without
3962 * the predicate. Nodes not satisfying
3963 * the predicate are removed.
3964 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003965 * @return Number of characters successfully parsed,
3966 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003967 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003968static int
Michal Vasko1c007172017-03-10 10:20:44 +01003969resolve_instid_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003970{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003971 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003972 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003973 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003974 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003975 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003976
Michal Vasko1f2cc332015-08-19 11:18:32 +02003977 assert(pred && node_match->count);
3978
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003979 idx = -1;
3980 parsed = 0;
3981
Michal Vaskob2f40be2016-09-08 16:03:48 +02003982 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003983 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003984 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003985 return -parsed+i;
3986 }
3987 parsed += i;
3988 pred += i;
3989
3990 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003991 /* pos */
3992 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003993 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003994 } else if (name[0] != '.') {
3995 /* list keys */
3996 if (pred_iter < 0) {
3997 pred_iter = 1;
3998 } else {
3999 ++pred_iter;
4000 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004001 }
4002
Michal Vaskof2f28a12016-09-09 12:43:06 +02004003 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004004 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004005 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004006 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004007 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004008 goto remove_instid;
4009 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004010
4011 target = node_match->node[j];
4012 /* check the value */
4013 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4014 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4015 goto remove_instid;
4016 }
4017
4018 } else if (!value) {
4019 /* keyless list position */
4020 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4021 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4022 goto remove_instid;
4023 }
4024
4025 if (idx != cur_idx) {
4026 goto remove_instid;
4027 }
4028
4029 } else {
4030 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004031 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004032 goto remove_instid;
4033 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004034
4035 /* key module must match the list module */
4036 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4037 || node_match->node[j]->schema->module->name[mod_len]) {
4038 goto remove_instid;
4039 }
4040 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004041 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004042 if (!target) {
4043 goto remove_instid;
4044 }
4045 if ((struct lys_node_leaf *)target->schema !=
4046 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4047 goto remove_instid;
4048 }
4049
4050 /* check the value */
4051 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4052 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4053 goto remove_instid;
4054 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004055 }
4056
Michal Vaskob2f40be2016-09-08 16:03:48 +02004057 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004058 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004059 continue;
4060
4061remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004062 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004063 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064 }
4065 } while (has_predicate);
4066
Michal Vaskob2f40be2016-09-08 16:03:48 +02004067 /* check that all list keys were specified */
4068 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004069 j = 0;
4070 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004071 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4072 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4073 /* not enough predicates, just remove the list instance */
4074 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004075 } else {
4076 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004077 }
4078 }
4079
4080 if (!node_match->count) {
4081 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4082 }
4083 }
4084
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085 return parsed;
4086}
4087
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004088int
Michal Vasko769f8032017-01-24 13:11:55 +01004089lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004090{
4091 struct lys_node *parent, *elem;
4092 struct lyxp_set set;
4093 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004094 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004095
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004096 if (check_place) {
4097 parent = node;
4098 while (parent) {
4099 if (parent->nodetype == LYS_GROUPING) {
4100 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004101 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004102 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004103 if (parent->nodetype == LYS_AUGMENT) {
4104 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004105 /* unresolved augment, skip for now (will be checked later) */
4106 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004107 } else {
4108 parent = ((struct lys_node_augment *)parent)->target;
4109 continue;
4110 }
4111 }
4112 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004113 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004114 }
4115
Michal Vasko769f8032017-01-24 13:11:55 +01004116 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4117 if (ret == -1) {
4118 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004119 }
4120
4121 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4122
4123 for (i = 0; i < set.used; ++i) {
4124 /* skip roots'n'stuff */
4125 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4126 /* XPath expression cannot reference "lower" status than the node that has the definition */
4127 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4128 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4129 return -1;
4130 }
4131
4132 if (parent) {
4133 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4134 if (!elem) {
4135 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004136 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004137 break;
4138 }
4139 }
4140 }
4141 }
4142
4143 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004144 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004145}
4146
Radek Krejcif71f48f2016-10-25 16:37:24 +02004147static int
4148check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4149{
4150 int i;
4151
4152 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004153 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4154 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004155 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
Radek Krejcif71f48f2016-10-25 16:37:24 +02004156 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4157 return -1;
4158 }
4159 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4160 * of leafref resolving (lys_leaf_add_leafref_target()) */
4161 } else if (type->base == LY_TYPE_UNION) {
4162 for (i = 0; i < type->info.uni.count; i++) {
4163 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4164 return -1;
4165 }
4166 }
4167 }
4168 return 0;
4169}
4170
Michal Vasko9e635ac2016-10-17 11:44:09 +02004171/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004172 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004173 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004174 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004175 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004176 * @param[in] clear Flag to clear all config flags if parent is LYS_NOTIF, LYS_INPUT, LYS_OUTPUT, LYS_RPC.
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004177 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004178 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004179 *
4180 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004181 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004182int
4183inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004184{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004185 struct lys_node_leaf *leaf;
4186
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004187 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004188 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004189 if (clear) {
4190 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004191 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004192 } else {
4193 if (node->flags & LYS_CONFIG_SET) {
4194 /* skip nodes with an explicit config value */
4195 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4196 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004197 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004198 return -1;
4199 }
4200 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004201 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004202
4203 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4204 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4205 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004206 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4207 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004208 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4209 return -1;
4210 }
4211 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004212 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004213 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004214 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004215 return -1;
4216 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004217 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4218 leaf = (struct lys_node_leaf *)node;
4219 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004220 return -1;
4221 }
4222 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004223 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004224
4225 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004226}
4227
Michal Vasko730dfdf2015-08-11 14:48:05 +02004228/**
Michal Vasko7178e692016-02-12 15:58:05 +01004229 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004230 *
Michal Vaskobb211122015-08-19 14:03:11 +02004231 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004232 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Radek Krejcib3142312016-11-09 11:04:12 +01004233 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004234 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004235 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004236 */
Michal Vasko7178e692016-02-12 15:58:05 +01004237static int
Radek Krejcib3142312016-11-09 11:04:12 +01004238resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004239{
Michal Vasko44ab1462017-05-18 13:18:36 +02004240 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004241 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004242 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004243
Michal Vasko15b36692016-08-26 15:29:54 +02004244 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004245 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004246
Michal Vaskobb520442017-05-23 10:55:18 +02004247 /* set it as not applied for now */
4248 aug->flags |= LYS_NOTAPPLIED;
4249
Michal Vasko15b36692016-08-26 15:29:54 +02004250 /* resolve target node */
Michal Vaskobb520442017-05-23 10:55:18 +02004251 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module),
Michal Vasko44ab1462017-05-18 13:18:36 +02004252 (const struct lys_node **)&aug->target);
Michal Vasko15b36692016-08-26 15:29:54 +02004253 if (rc == -1) {
4254 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004255 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004256 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4257 return -1;
4258 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004259 if (!aug->target) {
Michal Vasko15b36692016-08-26 15:29:54 +02004260 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4261 return EXIT_FAILURE;
4262 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004263
Michal Vaskod58d5962016-03-02 14:29:41 +01004264 /* check for mandatory nodes - if the target node is in another module
4265 * the added nodes cannot be mandatory
4266 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004267 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4268 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004269 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004270 }
4271
Michal Vasko07e89ef2016-03-03 13:28:57 +01004272 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004273 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004274 LY_TREE_FOR(aug->child, sub) {
4275 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4276 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4277 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4278 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004279 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004280 return -1;
4281 }
4282 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004283 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004284 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004285 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004286 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004287 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004288 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004289 return -1;
4290 }
4291 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004292 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004293 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004294 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004295 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004296 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004297 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004298 return -1;
4299 }
4300 }
4301 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004302 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004303 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004304 return -1;
4305 }
4306
Radek Krejcic071c542016-01-27 14:57:51 +01004307 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004308 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004309 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004310 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004311 }
4312 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004313
Michal Vasko44ab1462017-05-18 13:18:36 +02004314 if (!aug->child) {
4315 /* empty augment, nothing to connect, but it is techincally applied */
4316 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4317 aug->flags &= ~LYS_NOTAPPLIED;
4318 } else if (mod->implemented && apply_aug(aug, unres)) {
4319 /* we tried to connect it, we failed */
4320 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004321 }
4322
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004323 return EXIT_SUCCESS;
4324}
4325
Radek Krejcie534c132016-11-23 13:32:31 +01004326static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004327resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004328{
4329 enum LY_VLOG_ELEM vlog_type;
4330 void *vlog_node;
4331 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004332 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004333 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004334 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004335 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004336 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004337 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004338
4339 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004340 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004341 vlog_node = info->parent;
4342 vlog_type = LY_VLOG_LYS;
4343 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004344 case LYEXT_PAR_MODULE:
4345 case LYEXT_PAR_IMPORT:
4346 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004347 vlog_node = NULL;
4348 vlog_type = LY_VLOG_LYS;
4349 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004350 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004351 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004352 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004353 break;
4354 }
4355
4356 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004357 /* YIN */
4358
Radek Krejcie534c132016-11-23 13:32:31 +01004359 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004360 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004361 if (!mod) {
4362 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004363 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004364 }
4365
4366 /* find the extension definition */
4367 e = NULL;
4368 for (i = 0; i < mod->extensions_size; i++) {
4369 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4370 e = &mod->extensions[i];
4371 break;
4372 }
4373 }
4374 /* try submodules */
4375 for (j = 0; !e && j < mod->inc_size; j++) {
4376 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4377 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4378 e = &mod->inc[j].submodule->extensions[i];
4379 break;
4380 }
4381 }
4382 }
4383 if (!e) {
4384 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4385 return EXIT_FAILURE;
4386 }
4387
4388 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004389
Radek Krejci72b35992017-01-04 16:27:44 +01004390 if (e->plugin && e->plugin->check_position) {
4391 /* common part - we have plugin with position checking function, use it first */
4392 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4393 /* extension is not allowed here */
4394 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4395 return -1;
4396 }
4397 }
4398
Radek Krejci8d6b7422017-02-03 14:42:13 +01004399 /* extension type-specific part - allocation */
4400 if (e->plugin) {
4401 etype = e->plugin->type;
4402 } else {
4403 /* default type */
4404 etype = LYEXT_FLAG;
4405 }
4406 switch (etype) {
4407 case LYEXT_FLAG:
4408 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4409 break;
4410 case LYEXT_COMPLEX:
4411 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4412 break;
4413 case LYEXT_ERR:
4414 /* we never should be here */
4415 LOGINT;
4416 return -1;
4417 }
4418
4419 /* common part for all extension types */
4420 (*ext)->def = e;
4421 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004422 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004423 (*ext)->insubstmt = info->substmt;
4424 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004425 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004426
4427 if (!(e->flags & LYS_YINELEM) && e->argument) {
4428 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4429 if (!(*ext)->arg_value) {
4430 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4431 return -1;
4432 }
4433 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4434 }
4435
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004436 (*ext)->nodetype = LYS_EXT;
4437 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004438
Radek Krejci8d6b7422017-02-03 14:42:13 +01004439 /* extension type-specific part - parsing content */
4440 switch (etype) {
4441 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004442 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4443 if (!yin->ns) {
4444 /* garbage */
4445 lyxml_free(mod->ctx, yin);
4446 continue;
4447 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4448 /* standard YANG statements are not expected here */
4449 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4450 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004451 } else if (yin->ns == info->data.yin->ns &&
4452 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004453 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004454 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004455 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004456 return -1;
4457 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004458 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004459 yin->content = NULL;
4460 lyxml_free(mod->ctx, yin);
4461 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004462 /* extension instance */
4463 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4464 LYEXT_SUBSTMT_SELF, 0, unres)) {
4465 return -1;
4466 }
Radek Krejci72b35992017-01-04 16:27:44 +01004467
Radek Krejci72b35992017-01-04 16:27:44 +01004468 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004469 }
Radek Krejci72b35992017-01-04 16:27:44 +01004470 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004471 break;
4472 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004473 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004474 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4475 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004476 return -1;
4477 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004478 break;
4479 default:
4480 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004481 }
Radek Krejci72b35992017-01-04 16:27:44 +01004482
4483 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4484
Radek Krejcie534c132016-11-23 13:32:31 +01004485 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004486 /* YANG */
4487
PavolVicanc1807262017-01-31 18:00:27 +01004488 ext_prefix = (char *)(*ext)->def;
4489 tmp = strchr(ext_prefix, ':');
4490 if (!tmp) {
4491 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004492 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004493 }
4494 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004495
PavolVicanc1807262017-01-31 18:00:27 +01004496 /* get the module where the extension is supposed to be defined */
4497 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4498 if (!mod) {
4499 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4500 return EXIT_FAILURE;
4501 }
4502
4503 /* find the extension definition */
4504 e = NULL;
4505 for (i = 0; i < mod->extensions_size; i++) {
4506 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4507 e = &mod->extensions[i];
4508 break;
4509 }
4510 }
4511 /* try submodules */
4512 for (j = 0; !e && j < mod->inc_size; j++) {
4513 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4514 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4515 e = &mod->inc[j].submodule->extensions[i];
4516 break;
4517 }
4518 }
4519 }
4520 if (!e) {
4521 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4522 return EXIT_FAILURE;
4523 }
4524
4525 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4526
4527 if (e->plugin && e->plugin->check_position) {
4528 /* common part - we have plugin with position checking function, use it first */
4529 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4530 /* extension is not allowed here */
4531 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004532 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004533 }
4534 }
4535
PavolVican22e88682017-02-14 22:38:18 +01004536 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004537 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004538 (*ext)->def = e;
4539 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004540 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004541
PavolVicanb0d84102017-02-15 16:32:42 +01004542 if (e->argument && !(*ext)->arg_value) {
4543 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4544 goto error;
4545 }
4546
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004547 (*ext)->module = info->mod;
4548 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004549
PavolVican22e88682017-02-14 22:38:18 +01004550 /* extension type-specific part */
4551 if (e->plugin) {
4552 etype = e->plugin->type;
4553 } else {
4554 /* default type */
4555 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004556 }
PavolVican22e88682017-02-14 22:38:18 +01004557 switch (etype) {
4558 case LYEXT_FLAG:
4559 /* nothing change */
4560 break;
4561 case LYEXT_COMPLEX:
4562 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4563 if (!tmp_ext) {
4564 LOGMEM;
4565 goto error;
4566 }
4567 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4568 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004569 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004570 if (info->data.yang) {
4571 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004572 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4573 (struct lys_ext_instance_complex*)(*ext))) {
4574 goto error;
4575 }
4576 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4577 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004578 goto error;
4579 }
PavolVicana3876672017-02-21 15:49:51 +01004580 }
4581 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4582 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004583 }
PavolVican22e88682017-02-14 22:38:18 +01004584 break;
4585 case LYEXT_ERR:
4586 /* we never should be here */
4587 LOGINT;
4588 goto error;
4589 }
4590
PavolVican22e88682017-02-14 22:38:18 +01004591 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4592 goto error;
4593 }
4594 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004595 }
4596
4597 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004598error:
4599 free(ext_prefix);
4600 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004601}
4602
Michal Vasko730dfdf2015-08-11 14:48:05 +02004603/**
Pavol Vican855ca622016-09-05 13:07:54 +02004604 * @brief Resolve (find) choice default case. Does not log.
4605 *
4606 * @param[in] choic Choice to use.
4607 * @param[in] dflt Name of the default case.
4608 *
4609 * @return Pointer to the default node or NULL.
4610 */
4611static struct lys_node *
4612resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4613{
4614 struct lys_node *child, *ret;
4615
4616 LY_TREE_FOR(choic->child, child) {
4617 if (child->nodetype == LYS_USES) {
4618 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4619 if (ret) {
4620 return ret;
4621 }
4622 }
4623
4624 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004625 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004626 return child;
4627 }
4628 }
4629
4630 return NULL;
4631}
4632
4633/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004634 * @brief Resolve uses, apply augments, refines. Logs directly.
4635 *
Michal Vaskobb211122015-08-19 14:03:11 +02004636 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004637 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004638 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004639 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004640 */
Michal Vasko184521f2015-09-24 13:14:26 +02004641static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004642resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004643{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004644 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004645 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004646 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004647 struct lys_node_leaflist *llist;
4648 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004649 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004650 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004651 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004652 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004653 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004654 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004655
Michal Vasko71e1aa82015-08-12 12:17:51 +02004656 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004657
Radek Krejci93def382017-05-24 15:33:48 +02004658 /* check that the grouping is resolved (no unresolved uses inside) */
4659 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004660
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004661 if (!uses->grp->child) {
4662 /* grouping without children, warning was already displayed */
4663 return EXIT_SUCCESS;
4664 }
4665
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004666 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004667 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004668 if (node_aux->nodetype & LYS_GROUPING) {
4669 /* do not instantiate groupings from groupings */
4670 continue;
4671 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004672 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004673 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004674 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004675 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004676 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004677 }
Pavol Vican55abd332016-07-12 15:54:49 +02004678 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004679 LY_TREE_FOR((uses->parent) ? *lys_child(uses->parent, LYS_USES) : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004680 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004681 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004682 }
4683 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004684 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004685
Michal Vaskodef0db12015-10-07 13:22:48 +02004686 /* we managed to copy the grouping, the rest must be possible to resolve */
4687
Pavol Vican855ca622016-09-05 13:07:54 +02004688 if (uses->refine_size) {
4689 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4690 if (!refine_nodes) {
4691 LOGMEM;
4692 goto fail;
4693 }
4694 }
4695
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004696 /* apply refines */
4697 for (i = 0; i < uses->refine_size; i++) {
4698 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004699 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4700 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004701 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004702 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004703 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004704 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004705 }
4706
Radek Krejci1d82ef62015-08-07 14:44:40 +02004707 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004708 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004709 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004710 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004711 }
Pavol Vican855ca622016-09-05 13:07:54 +02004712 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004713
4714 /* description on any nodetype */
4715 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004716 lydict_remove(ctx, node->dsc);
4717 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004718 }
4719
4720 /* reference on any nodetype */
4721 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004722 lydict_remove(ctx, node->ref);
4723 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004724 }
4725
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004726 /* config on any nodetype,
4727 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4728 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004729 node->flags &= ~LYS_CONFIG_MASK;
4730 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004731 }
4732
4733 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004734 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004735 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004736 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004737 leaf = (struct lys_node_leaf *)node;
4738
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004739 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004740 lydict_remove(ctx, leaf->dflt);
4741 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4742
4743 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004744 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4745 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004746 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004747 }
Radek Krejci200bf712016-08-16 17:11:04 +02004748 } else if (node->nodetype == LYS_LEAFLIST) {
4749 /* leaf-list */
4750 llist = (struct lys_node_leaflist *)node;
4751
4752 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004753 for (j = 0; j < llist->dflt_size; j++) {
4754 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004755 }
4756 free(llist->dflt);
4757
4758 /* copy the default set from refine */
4759 llist->dflt_size = rfn->dflt_size;
4760 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
Radek Krejci542ab142017-01-23 15:57:08 +01004761 for (j = 0; j < llist->dflt_size; j++) {
4762 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004763 }
4764
4765 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004766 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004767 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004768 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004769 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004770 }
4771 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004772 }
4773 }
4774
4775 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004776 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004777 /* remove current value */
4778 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004779
Radek Krejcibf285832017-01-26 16:05:41 +01004780 /* set new value */
4781 node->flags |= (rfn->flags & LYS_MAND_MASK);
4782
Pavol Vican855ca622016-09-05 13:07:54 +02004783 if (rfn->flags & LYS_MAND_TRUE) {
4784 /* check if node has default value */
4785 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004786 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4787 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004788 goto fail;
4789 }
4790 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004791 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4792 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004793 goto fail;
4794 }
4795 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004796 }
4797
4798 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004799 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4800 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4801 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004802 }
4803
4804 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004805 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004806 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004807 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004808 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004809 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004810 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004811 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004812 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004813 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004814 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004815 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004816 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004817 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004818 }
4819 }
4820
4821 /* must in leaf, leaf-list, list, container or anyxml */
4822 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004823 switch (node->nodetype) {
4824 case LYS_LEAF:
4825 old_size = &((struct lys_node_leaf *)node)->must_size;
4826 old_must = &((struct lys_node_leaf *)node)->must;
4827 break;
4828 case LYS_LEAFLIST:
4829 old_size = &((struct lys_node_leaflist *)node)->must_size;
4830 old_must = &((struct lys_node_leaflist *)node)->must;
4831 break;
4832 case LYS_LIST:
4833 old_size = &((struct lys_node_list *)node)->must_size;
4834 old_must = &((struct lys_node_list *)node)->must;
4835 break;
4836 case LYS_CONTAINER:
4837 old_size = &((struct lys_node_container *)node)->must_size;
4838 old_must = &((struct lys_node_container *)node)->must;
4839 break;
4840 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004841 case LYS_ANYDATA:
4842 old_size = &((struct lys_node_anydata *)node)->must_size;
4843 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004844 break;
4845 default:
4846 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004847 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004848 }
4849
4850 size = *old_size + rfn->must_size;
4851 must = realloc(*old_must, size * sizeof *rfn->must);
4852 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004853 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004854 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004855 }
Pavol Vican855ca622016-09-05 13:07:54 +02004856 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004857 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004858 lys_ext_dup(rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejci5138e9f2017-04-12 13:10:46 +02004859 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004860 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4861 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4862 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4863 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4864 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004865 }
4866
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004867 *old_must = must;
4868 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004869
4870 /* check XPath dependencies again */
4871 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4872 goto fail;
4873 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004874 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004875
4876 /* if-feature in leaf, leaf-list, list, container or anyxml */
4877 if (rfn->iffeature_size) {
4878 old_size = &node->iffeature_size;
4879 old_iff = &node->iffeature;
4880
4881 size = *old_size + rfn->iffeature_size;
4882 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4883 if (!iff) {
4884 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004885 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004886 }
Pavol Vican855ca622016-09-05 13:07:54 +02004887 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4888 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004889 if (usize1) {
4890 /* there is something to duplicate */
4891 /* duplicate compiled expression */
4892 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4893 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004894 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004895
4896 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004897 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4898 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004899 }
4900 }
4901
4902 *old_iff = iff;
4903 *old_size = size;
4904 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004905 }
4906
4907 /* apply augments */
4908 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004909 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004910 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004911 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004912 }
4913 }
4914
Pavol Vican855ca622016-09-05 13:07:54 +02004915 /* check refines */
4916 for (i = 0; i < uses->refine_size; i++) {
4917 node = refine_nodes[i];
4918 rfn = &uses->refine[i];
4919
4920 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004921 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004922 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004923 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004924 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4925 (rfn->flags & LYS_CONFIG_W)) {
4926 /* setting config true under config false is prohibited */
4927 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004928 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004929 "changing config from 'false' to 'true' is prohibited while "
4930 "the target's parent is still config 'false'.");
4931 goto fail;
4932 }
4933
4934 /* inherit config change to the target children */
4935 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4936 if (rfn->flags & LYS_CONFIG_W) {
4937 if (iter->flags & LYS_CONFIG_SET) {
4938 /* config is set explicitely, go to next sibling */
4939 next = NULL;
4940 goto nextsibling;
4941 }
4942 } else { /* LYS_CONFIG_R */
4943 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4944 /* error - we would have config data under status data */
4945 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004946 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004947 "changing config from 'true' to 'false' is prohibited while the target "
4948 "has still a children with explicit config 'true'.");
4949 goto fail;
4950 }
4951 }
4952 /* change config */
4953 iter->flags &= ~LYS_CONFIG_MASK;
4954 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4955
4956 /* select next iter - modified LY_TREE_DFS_END */
4957 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4958 next = NULL;
4959 } else {
4960 next = iter->child;
4961 }
4962nextsibling:
4963 if (!next) {
4964 /* try siblings */
4965 next = iter->next;
4966 }
4967 while (!next) {
4968 /* parent is already processed, go to its sibling */
4969 iter = lys_parent(iter);
4970
4971 /* no siblings, go back through parents */
4972 if (iter == node) {
4973 /* we are done, no next element to process */
4974 break;
4975 }
4976 next = iter->next;
4977 }
4978 }
4979 }
4980
4981 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004982 if (rfn->dflt_size) {
4983 if (node->nodetype == LYS_CHOICE) {
4984 /* choice */
4985 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4986 rfn->dflt[0]);
4987 if (!((struct lys_node_choice *)node)->dflt) {
4988 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4989 goto fail;
4990 }
4991 if (lyp_check_mandatory_choice(node)) {
4992 goto fail;
4993 }
Pavol Vican855ca622016-09-05 13:07:54 +02004994 }
4995 }
4996
4997 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02004998 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004999 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005000 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5001 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005002 goto fail;
5003 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005004 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005005 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005006 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5007 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005008 goto fail;
5009 }
5010 }
5011
5012 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005013 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005014 if (node->nodetype == LYS_LEAFLIST) {
5015 llist = (struct lys_node_leaflist *)node;
5016 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005017 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5018 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005019 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5020 goto fail;
5021 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005022 } else if (node->nodetype == LYS_LEAF) {
5023 leaf = (struct lys_node_leaf *)node;
5024 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005025 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5026 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005027 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5028 goto fail;
5029 }
Pavol Vican855ca622016-09-05 13:07:54 +02005030 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005031
Pavol Vican855ca622016-09-05 13:07:54 +02005032 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005033 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005034 for (parent = node->parent;
5035 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5036 parent = parent->parent) {
5037 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5038 /* stop also on presence containers */
5039 break;
5040 }
5041 }
5042 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5043 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5044 if (lyp_check_mandatory_choice(parent)) {
5045 goto fail;
5046 }
5047 }
5048 }
5049 }
5050 free(refine_nodes);
5051
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005052 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005053
5054fail:
5055 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5056 lys_node_free(iter, NULL, 0);
5057 }
Pavol Vican855ca622016-09-05 13:07:54 +02005058 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005059 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005060}
5061
Radek Krejci83a4bac2017-02-07 15:53:04 +01005062void
5063resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005064{
5065 int i;
5066
5067 assert(der && base);
5068
Radek Krejci018f1f52016-08-03 16:01:20 +02005069 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005070 /* create a set for backlinks if it does not exist */
5071 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005072 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005073 /* store backlink */
5074 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005075
Radek Krejci85a54be2016-10-20 12:39:56 +02005076 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005077 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005078 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005079 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005080}
5081
Michal Vasko730dfdf2015-08-11 14:48:05 +02005082/**
5083 * @brief Resolve base identity recursively. Does not log.
5084 *
5085 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005086 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005087 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005088 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005089 *
Radek Krejci219fa612016-08-15 10:36:51 +02005090 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005091 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005092static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005093resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005094 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005095{
Michal Vaskof02e3742015-08-05 16:27:02 +02005096 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005097 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005098
Radek Krejcicf509982015-12-15 09:22:44 +01005099 assert(ret);
5100
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005101 /* search module */
5102 for (i = 0; i < module->ident_size; i++) {
5103 if (!strcmp(basename, module->ident[i].name)) {
5104
5105 if (!ident) {
5106 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005107 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005108 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005109 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005110 }
5111
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005112 base = &module->ident[i];
5113 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005114 }
5115 }
5116
5117 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005118 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5119 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5120 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005121
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005122 if (!ident) {
5123 *ret = &module->inc[j].submodule->ident[i];
5124 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005125 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005126
5127 base = &module->inc[j].submodule->ident[i];
5128 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005129 }
5130 }
5131 }
5132
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005133matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005134 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005135 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005136 /* is it already completely resolved? */
5137 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005138 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005139 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5140
5141 /* simple check for circular reference,
5142 * the complete check is done as a side effect of using only completely
5143 * resolved identities (previous check of unres content) */
5144 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5145 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5146 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005147 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005148 }
5149
Radek Krejci06f64ed2016-08-15 11:07:44 +02005150 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005151 }
5152 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005153
Radek Krejcibabbff82016-02-19 13:31:37 +01005154 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005155 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005156 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005157 }
5158
Radek Krejci219fa612016-08-15 10:36:51 +02005159 /* base not found (maybe a forward reference) */
5160 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005161}
5162
Michal Vasko730dfdf2015-08-11 14:48:05 +02005163/**
5164 * @brief Resolve base identity. Logs directly.
5165 *
5166 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005167 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005168 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005169 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005170 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005171 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005172 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005173 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005174static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005175resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005176 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005177{
5178 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005179 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005180 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005181 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005182 struct lys_module *mod;
5183
5184 assert((ident && !type) || (!ident && type));
5185
5186 if (!type) {
5187 /* have ident to resolve */
5188 ret = &target;
5189 flags = ident->flags;
5190 mod = ident->module;
5191 } else {
5192 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005193 ++type->info.ident.count;
5194 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5195 if (!type->info.ident.ref) {
5196 LOGMEM;
5197 return -1;
5198 }
5199
5200 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005201 flags = type->parent->flags;
5202 mod = type->parent->module;
5203 }
Michal Vaskof2006002016-04-21 16:28:15 +02005204 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005205
5206 /* search for the base identity */
5207 name = strchr(basename, ':');
5208 if (name) {
5209 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005210 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005211 name++;
5212
Michal Vasko2d851a92015-10-20 16:16:36 +02005213 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005214 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005215 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005216 }
5217 } else {
5218 name = basename;
5219 }
5220
Radek Krejcic071c542016-01-27 14:57:51 +01005221 /* get module where to search */
5222 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5223 if (!module) {
5224 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005225 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005226 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005227 }
5228
Radek Krejcic071c542016-01-27 14:57:51 +01005229 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005230 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5231 if (!rc) {
5232 assert(*ret);
5233
5234 /* check status */
5235 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5236 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5237 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005238 } else if (ident) {
5239 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005240 if (lys_main_module(mod)->implemented) {
5241 /* in case of the implemented identity, maintain backlinks to it
5242 * from the base identities to make it available when resolving
5243 * data with the identity values (not implemented identity is not
5244 * allowed as an identityref value). */
5245 resolve_identity_backlink_update(ident, *ret);
5246 }
Radek Krejci219fa612016-08-15 10:36:51 +02005247 }
5248 } else if (rc == EXIT_FAILURE) {
5249 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005250 if (type) {
5251 --type->info.ident.count;
5252 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005253 }
5254
Radek Krejci219fa612016-08-15 10:36:51 +02005255 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005256}
5257
Radek Krejci9e6af732017-04-27 14:40:25 +02005258/*
5259 * 1 - true (der is derived from base)
5260 * 0 - false (der is not derived from base)
5261 */
5262static int
5263search_base_identity(struct lys_ident *der, struct lys_ident *base)
5264{
5265 int i;
5266
5267 if (der == base) {
5268 return 1;
5269 } else {
5270 for(i = 0; i < der->base_size; i++) {
5271 if (search_base_identity(der->base[i], base) == 1) {
5272 return 1;
5273 }
5274 }
5275 }
5276
5277 return 0;
5278}
5279
Michal Vasko730dfdf2015-08-11 14:48:05 +02005280/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005281 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005282 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005283 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005284 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005285 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005286 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005287 *
5288 * @return Pointer to the identity resolvent, NULL on error.
5289 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005290struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005291resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005292{
Radek Krejci9e6af732017-04-27 14:40:25 +02005293 const char *mod_name, *name;
5294 int mod_name_len, rc, i, j;
5295 int make_implemented = 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02005296 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005297 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005298 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005299
Radek Krejci9e6af732017-04-27 14:40:25 +02005300 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005301
Michal Vaskof2d43962016-09-02 11:10:16 +02005302 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005303 return NULL;
5304 }
5305
Michal Vaskoc633ca02015-08-21 14:03:51 +02005306 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005307 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005308 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005309 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005310 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005311 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005312 return NULL;
5313 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005314
5315 m = lys_main_module(mod); /* shortcut */
5316 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5317 /* identity is defined in the same module as node */
5318 imod = m;
5319 } else if (dflt) {
5320 /* solving identityref in default definition in schema -
5321 * find the identity's module in the imported modules list to have a correct revision */
5322 for (i = 0; i < mod->imp_size; i++) {
5323 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5324 imod = mod->imp[i].module;
5325 break;
5326 }
5327 }
5328 } else {
5329 /* solving identityref in data - get the (implemented) module from the context */
5330 u = 0;
5331 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5332 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5333 break;
5334 }
5335 }
5336 }
5337 if (!imod) {
5338 goto fail;
5339 }
5340
5341 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5342 /* we are solving default statement in schema AND the type is not referencing the same schema,
5343 * THEN, we may need to make the module with the identity implemented, but only if it really
5344 * contains the identity */
5345 if (!imod->implemented) {
5346 cur = NULL;
5347 /* get the identity in the module */
5348 for (i = 0; i < imod->ident_size; i++) {
5349 if (!strcmp(name, imod->ident[i].name)) {
5350 cur = &imod->ident[i];
5351 break;
5352 }
5353 }
5354 if (!cur) {
5355 /* go through includes */
5356 for (j = 0; j < imod->inc_size; j++) {
5357 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5358 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5359 cur = &imod->inc[j].submodule->ident[i];
5360 break;
5361 }
5362 }
5363 }
5364 if (!cur) {
5365 goto fail;
5366 }
5367 }
5368
5369 /* check that identity is derived from one of the type's base */
5370 while (type->der) {
5371 for (i = 0; i < type->info.ident.count; i++) {
5372 if (search_base_identity(cur, type->info.ident.ref[i])) {
5373 /* cur's base matches the type's base */
5374 make_implemented = 1;
5375 goto match;
5376 }
5377 }
5378 type = &type->der->type;
5379 }
5380 /* matching base not found */
5381 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5382 goto fail;
5383 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005384 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005385
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005386 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005387 while (type->der) {
5388 for (i = 0; i < type->info.ident.count; ++i) {
5389 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005390
Radek Krejci85a54be2016-10-20 12:39:56 +02005391 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005392 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005393 for (u = 0; u < cur->der->number; u++) {
5394 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005395 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005396 /* we have match */
5397 cur = der;
5398 goto match;
5399 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005400 }
5401 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005402 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005403 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005404 }
5405
Radek Krejci9e6af732017-04-27 14:40:25 +02005406fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005407 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005408 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005409
5410match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005411 for (i = 0; i < cur->iffeature_size; i++) {
5412 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005413 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005414 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005415 return NULL;
5416 }
5417 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005418 if (make_implemented) {
5419 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5420 imod->name, cur->name, mod->name);
5421 if (lys_set_implemented(imod)) {
5422 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5423 imod->name, cur->name);
5424 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5425 goto fail;
5426 }
5427 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005428 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005429}
5430
Michal Vasko730dfdf2015-08-11 14:48:05 +02005431/**
Michal Vaskobb211122015-08-19 14:03:11 +02005432 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005433 *
Michal Vaskobb211122015-08-19 14:03:11 +02005434 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005435 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005436 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005437 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005438 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005439static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005440resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005441{
Radek Krejci93def382017-05-24 15:33:48 +02005442 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005443 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005444
Radek Krejci6ff885d2017-01-03 14:06:22 +01005445 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
Radek Krejci93def382017-05-24 15:33:48 +02005446 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5447 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5448 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005449 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 +02005450
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005451 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005452 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5453 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005454 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005455 return -1;
5456 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005457 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005458 return -1;
5459 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005460 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005461 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5462 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5463 return -1;
5464 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005465 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005466 }
Michal Vasko92981a62016-10-14 10:25:16 +02005467 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005468 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005469 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005470 }
5471
Radek Krejci93def382017-05-24 15:33:48 +02005472 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005473 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005474 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5475 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5476 return -1;
5477 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005478 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005479 } else {
5480 /* instantiate grouping only when it is completely resolved */
5481 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005482 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005483 return EXIT_FAILURE;
5484 }
5485
Radek Krejci48464ed2016-03-17 15:44:09 +01005486 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005487 if (!rc) {
5488 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005489 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005490 assert(((struct lys_node_grp *)par_grp)->unres_count);
5491 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005492 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005493 }
Radek Krejcicf509982015-12-15 09:22:44 +01005494
5495 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005496 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005497 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005498 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005499 return -1;
5500 }
5501
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005502 return EXIT_SUCCESS;
5503 }
5504
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005505 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005506}
5507
Michal Vasko730dfdf2015-08-11 14:48:05 +02005508/**
Michal Vasko9957e592015-08-17 15:04:09 +02005509 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005510 *
Michal Vaskobb211122015-08-19 14:03:11 +02005511 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005512 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005513 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005514 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005515 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005516static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005517resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005518{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005519 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005520 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005521 char *s = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005522
5523 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005524 if (!list->child) {
5525 /* no child, possible forward reference */
5526 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5527 return EXIT_FAILURE;
5528 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005529 /* get the key name */
5530 if ((value = strpbrk(keys_str, " \t\n"))) {
5531 len = value - keys_str;
5532 while (isspace(value[0])) {
5533 value++;
5534 }
5535 } else {
5536 len = strlen(keys_str);
5537 }
5538
Radek Krejcia98048c2017-05-24 16:35:48 +02005539 if (list->keys[i]) {
5540 /* skip already resolved keys */
5541 goto next;
5542 }
5543
Michal Vaskobb520442017-05-23 10:55:18 +02005544 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5545 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005546 if (rc) {
Radek Krejcia98048c2017-05-24 16:35:48 +02005547 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005548 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005549 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005550
Radek Krejci48464ed2016-03-17 15:44:09 +01005551 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005552 /* check_key logs */
5553 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005554 }
5555
Radek Krejcicf509982015-12-15 09:22:44 +01005556 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005557 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005558 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5559 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005560 return -1;
5561 }
5562
Radek Krejcia98048c2017-05-24 16:35:48 +02005563 /* default value - is ignored, keep it but print a warning */
5564 if (list->keys[i]->dflt) {
5565 /* log is not hidden only in case this resolving fails and in such a case
5566 * we cannot get here
5567 */
5568 assert(*ly_vlog_hide_location());
5569 ly_vlog_hide(0);
5570 LOGWRN("Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
5571 list->keys[i]->name, s = lys_path((struct lys_node*)list));
5572 ly_vlog_hide(1);
5573 free(s);
5574 }
5575
5576next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005577 /* prepare for next iteration */
5578 while (value && isspace(value[0])) {
5579 value++;
5580 }
5581 keys_str = value;
5582 }
5583
Michal Vaskof02e3742015-08-05 16:27:02 +02005584 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005585}
5586
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005587/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005588 * @brief Resolve (check) all must conditions of \p node.
5589 * Logs directly.
5590 *
5591 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005592 * @param[in] inout_parent If set, must in input or output parent of node->schema will be resolved.
Michal Vaskobf19d252015-10-08 15:39:17 +02005593 *
5594 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5595 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005596static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005597resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005598{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005599 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005600 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005601 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005602 struct lys_restr *must;
5603 struct lyxp_set set;
5604
5605 assert(node);
5606 memset(&set, 0, sizeof set);
5607
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005608 if (inout_parent) {
5609 for (schema = lys_parent(node->schema);
5610 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5611 schema = lys_parent(schema));
5612 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5613 LOGINT;
5614 return -1;
5615 }
5616 must_size = ((struct lys_node_inout *)schema)->must_size;
5617 must = ((struct lys_node_inout *)schema)->must;
5618
Michal Vasko3cfa3182017-01-17 10:00:58 +01005619 node_flags = schema->flags;
5620
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005621 /* context node is the RPC/action */
5622 node = node->parent;
5623 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5624 LOGINT;
5625 return -1;
5626 }
5627 } else {
5628 switch (node->schema->nodetype) {
5629 case LYS_CONTAINER:
5630 must_size = ((struct lys_node_container *)node->schema)->must_size;
5631 must = ((struct lys_node_container *)node->schema)->must;
5632 break;
5633 case LYS_LEAF:
5634 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5635 must = ((struct lys_node_leaf *)node->schema)->must;
5636 break;
5637 case LYS_LEAFLIST:
5638 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5639 must = ((struct lys_node_leaflist *)node->schema)->must;
5640 break;
5641 case LYS_LIST:
5642 must_size = ((struct lys_node_list *)node->schema)->must_size;
5643 must = ((struct lys_node_list *)node->schema)->must;
5644 break;
5645 case LYS_ANYXML:
5646 case LYS_ANYDATA:
5647 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5648 must = ((struct lys_node_anydata *)node->schema)->must;
5649 break;
5650 case LYS_NOTIF:
5651 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5652 must = ((struct lys_node_notif *)node->schema)->must;
5653 break;
5654 default:
5655 must_size = 0;
5656 break;
5657 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005658
5659 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005660 }
5661
5662 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005663 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005664 return -1;
5665 }
5666
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005667 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005668
Michal Vasko8146d4c2016-05-09 15:50:29 +02005669 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005670 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005671 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5672 } else {
5673 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5674 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005675 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005676 }
5677 if (must[i].eapptag) {
5678 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5679 }
5680 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005681 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005682 }
5683 }
5684
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005685 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005686}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005687
Michal Vaskobf19d252015-10-08 15:39:17 +02005688/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005689 * @brief Resolve (find) when condition schema context node. Does not log.
5690 *
5691 * @param[in] schema Schema node with the when condition.
5692 * @param[out] ctx_snode When schema context node.
5693 * @param[out] ctx_snode_type Schema context node type.
5694 */
5695void
5696resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5697{
5698 const struct lys_node *sparent;
5699
5700 /* find a not schema-only node */
5701 *ctx_snode_type = LYXP_NODE_ELEM;
5702 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5703 if (schema->nodetype == LYS_AUGMENT) {
5704 sparent = ((struct lys_node_augment *)schema)->target;
5705 } else {
5706 sparent = schema->parent;
5707 }
5708 if (!sparent) {
5709 /* context node is the document root (fake root in our case) */
5710 if (schema->flags & LYS_CONFIG_W) {
5711 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5712 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005713 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005714 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005715 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005716 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005717 break;
5718 }
5719 schema = sparent;
5720 }
5721
5722 *ctx_snode = (struct lys_node *)schema;
5723}
5724
5725/**
Michal Vaskocf024702015-10-08 15:01:42 +02005726 * @brief Resolve (find) when condition context node. Does not log.
5727 *
5728 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005729 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005730 * @param[out] ctx_node Context node.
5731 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005732 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005733 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005734 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005735static int
5736resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5737 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005738{
Michal Vaskocf024702015-10-08 15:01:42 +02005739 struct lyd_node *parent;
5740 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005741 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005742 uint16_t i, data_depth, schema_depth;
5743
Michal Vasko508a50d2016-09-07 14:50:33 +02005744 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005745
Michal Vaskofe989752016-09-08 08:47:26 +02005746 if (node_type == LYXP_NODE_ELEM) {
5747 /* standard element context node */
5748 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5749 for (sparent = schema, schema_depth = 0;
5750 sparent;
5751 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5752 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5753 ++schema_depth;
5754 }
Michal Vaskocf024702015-10-08 15:01:42 +02005755 }
Michal Vaskofe989752016-09-08 08:47:26 +02005756 if (data_depth < schema_depth) {
5757 return -1;
5758 }
Michal Vaskocf024702015-10-08 15:01:42 +02005759
Michal Vasko956e8542016-08-26 09:43:35 +02005760 /* find the corresponding data node */
5761 for (i = 0; i < data_depth - schema_depth; ++i) {
5762 node = node->parent;
5763 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005764 if (node->schema != schema) {
5765 return -1;
5766 }
Michal Vaskofe989752016-09-08 08:47:26 +02005767 } else {
5768 /* root context node */
5769 while (node->parent) {
5770 node = node->parent;
5771 }
5772 while (node->prev->next) {
5773 node = node->prev;
5774 }
Michal Vaskocf024702015-10-08 15:01:42 +02005775 }
5776
Michal Vaskoa59495d2016-08-22 09:18:58 +02005777 *ctx_node = node;
5778 *ctx_node_type = node_type;
5779 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005780}
5781
Michal Vasko76c3bd32016-08-24 16:02:52 +02005782/**
5783 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005784 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005785 *
5786 * @param[in] snode Schema node, whose children instances need to be unlinked.
5787 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5788 * it is moved to point to another sibling still in the original tree.
5789 * @param[in,out] ctx_node When context node, adjusted if needed.
5790 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5791 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5792 * Ordering may change, but there will be no semantic change.
5793 *
5794 * @return EXIT_SUCCESS on success, -1 on error.
5795 */
5796static int
5797resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5798 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5799{
5800 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005801 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005802
5803 switch (snode->nodetype) {
5804 case LYS_AUGMENT:
5805 case LYS_USES:
5806 case LYS_CHOICE:
5807 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005808 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005809 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005810 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5811 continue;
5812 }
5813
5814 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005815 return -1;
5816 }
5817 }
5818 break;
5819 case LYS_CONTAINER:
5820 case LYS_LIST:
5821 case LYS_LEAF:
5822 case LYS_LEAFLIST:
5823 case LYS_ANYXML:
5824 case LYS_ANYDATA:
5825 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5826 if (elem->schema == snode) {
5827
5828 if (elem == *ctx_node) {
5829 /* We are going to unlink our context node! This normally cannot happen,
5830 * but we use normal top-level data nodes for faking a document root node,
5831 * so if this is the context node, we just use the next top-level node.
5832 * Additionally, it can even happen that there are no top-level data nodes left,
5833 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5834 * lyxp_eval() can handle this special situation.
5835 */
5836 if (ctx_node_type == LYXP_NODE_ELEM) {
5837 LOGINT;
5838 return -1;
5839 }
5840
5841 if (elem->prev == elem) {
5842 /* unlinking last top-level element, use an empty data tree */
5843 *ctx_node = NULL;
5844 } else {
5845 /* in this case just use the previous/last top-level data node */
5846 *ctx_node = elem->prev;
5847 }
5848 } else if (elem == *node) {
5849 /* We are going to unlink the currently processed node. This does not matter that
5850 * much, but we would lose access to the original data tree, so just move our
5851 * pointer somewhere still inside it.
5852 */
5853 if ((*node)->prev != *node) {
5854 *node = (*node)->prev;
5855 } else {
5856 /* the processed node with sibings were all unlinked, oh well */
5857 *node = NULL;
5858 }
5859 }
5860
5861 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005862 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005863 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005864 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005865 LOGINT;
5866 return -1;
5867 }
5868 } else {
5869 *unlinked_nodes = elem;
5870 }
5871
5872 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5873 /* there can be only one instance */
5874 break;
5875 }
5876 }
5877 }
5878 break;
5879 default:
5880 LOGINT;
5881 return -1;
5882 }
5883
5884 return EXIT_SUCCESS;
5885}
5886
5887/**
5888 * @brief Relink the unlinked nodes back.
5889 *
5890 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5891 * we simply need a sibling from the original data tree.
5892 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5893 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5894 * or the sibling of \p unlinked_nodes.
5895 *
5896 * @return EXIT_SUCCESS on success, -1 on error.
5897 */
5898static int
5899resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5900{
5901 struct lyd_node *elem;
5902
5903 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005904 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005905 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005906 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005907 return -1;
5908 }
5909 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005910 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005911 return -1;
5912 }
5913 }
5914 }
5915
5916 return EXIT_SUCCESS;
5917}
5918
Radek Krejci03b71f72016-03-16 11:10:09 +01005919int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005920resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005921{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005922 int ret = 0;
5923 uint8_t must_size;
5924 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005925
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005926 assert(node);
5927
5928 schema = node->schema;
5929
5930 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005931 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005932 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005933 must_size = ((struct lys_node_container *)schema)->must_size;
5934 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005935 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005936 must_size = ((struct lys_node_leaf *)schema)->must_size;
5937 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005938 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005939 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5940 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005941 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005942 must_size = ((struct lys_node_list *)schema)->must_size;
5943 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005944 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005945 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005946 must_size = ((struct lys_node_anydata *)schema)->must_size;
5947 break;
5948 case LYS_NOTIF:
5949 must_size = ((struct lys_node_notif *)schema)->must_size;
5950 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005951 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005952 must_size = 0;
5953 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005954 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005955
5956 if (must_size) {
5957 ++ret;
5958 }
5959
5960 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5961 if (!node->prev->next) {
5962 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5963 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5964 ret += 0x2;
5965 }
5966 }
5967
5968 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005969}
5970
5971int
Radek Krejci46165822016-08-26 14:06:27 +02005972resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005973{
Radek Krejci46165822016-08-26 14:06:27 +02005974 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005975
Radek Krejci46165822016-08-26 14:06:27 +02005976 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005977
Radek Krejci46165822016-08-26 14:06:27 +02005978 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005979 return 1;
5980 }
5981
Radek Krejci46165822016-08-26 14:06:27 +02005982 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005983 goto check_augment;
5984
Radek Krejci46165822016-08-26 14:06:27 +02005985 while (parent) {
5986 /* stop conditions */
5987 if (!mode) {
5988 /* stop on node that can be instantiated in data tree */
5989 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5990 break;
5991 }
5992 } else {
5993 /* stop on the specified node */
5994 if (parent == stop) {
5995 break;
5996 }
5997 }
5998
5999 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006000 return 1;
6001 }
6002check_augment:
6003
6004 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006005 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006006 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006007 }
6008 parent = lys_parent(parent);
6009 }
6010
6011 return 0;
6012}
6013
Michal Vaskocf024702015-10-08 15:01:42 +02006014/**
6015 * @brief Resolve (check) all when conditions relevant for \p node.
6016 * Logs directly.
6017 *
6018 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02006019 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006020 * @return
6021 * -1 - error, ly_errno is set
6022 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02006023 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01006024 * 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 +02006025 */
Radek Krejci46165822016-08-26 14:06:27 +02006026int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006027resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02006028{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006029 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006030 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006031 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006032 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02006033 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006034
6035 assert(node);
6036 memset(&set, 0, sizeof set);
6037
Michal Vasko78d97e22017-02-21 09:54:38 +01006038 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006039 /* make the node dummy for the evaluation */
6040 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006041 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6042 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006043 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006044 if (rc) {
6045 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006046 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006047 }
Radek Krejci51093642016-03-29 10:14:59 +02006048 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006049 }
6050
Radek Krejci03b71f72016-03-16 11:10:09 +01006051 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006052 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006053 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006054 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006055 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006056 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6057 ((struct lys_node_container *)node->schema)->when->cond);
6058 } else {
6059 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
6060 goto cleanup;
6061 }
Michal Vaskocf024702015-10-08 15:01:42 +02006062 }
Radek Krejci51093642016-03-29 10:14:59 +02006063
6064 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006065 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006066 }
6067
Michal Vasko90fc2a32016-08-24 15:58:58 +02006068 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006069 goto check_augment;
6070
6071 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006072 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6073 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006074 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006075 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006076 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006077 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006078 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006079 }
6080 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006081
6082 unlinked_nodes = NULL;
6083 /* we do not want our node pointer to change */
6084 tmp_node = node;
6085 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6086 if (rc) {
6087 goto cleanup;
6088 }
6089
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006090 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6091 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006092
6093 if (unlinked_nodes && ctx_node) {
6094 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6095 rc = -1;
6096 goto cleanup;
6097 }
6098 }
6099
Radek Krejci03b71f72016-03-16 11:10:09 +01006100 if (rc) {
6101 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006102 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006103 }
Radek Krejci51093642016-03-29 10:14:59 +02006104 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006105 }
6106
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006107 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006108 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006109 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006110 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6111 ((struct lys_node_uses *)sparent)->when->cond);
6112 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006113 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006114 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6115 goto cleanup;
6116 }
Michal Vaskocf024702015-10-08 15:01:42 +02006117 }
Radek Krejci51093642016-03-29 10:14:59 +02006118
6119 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006120 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006121 }
6122
6123check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006124 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006125 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006126 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006127 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006128 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006129 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006130 }
6131 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006132
6133 unlinked_nodes = NULL;
6134 tmp_node = node;
6135 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6136 if (rc) {
6137 goto cleanup;
6138 }
6139
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006140 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6141 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006142
6143 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6144 * so the tree did not actually change and there is nothing for us to do
6145 */
6146 if (unlinked_nodes && ctx_node) {
6147 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6148 rc = -1;
6149 goto cleanup;
6150 }
6151 }
6152
Radek Krejci03b71f72016-03-16 11:10:09 +01006153 if (rc) {
6154 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006155 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006156 }
Radek Krejci51093642016-03-29 10:14:59 +02006157 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006158 }
6159
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006160 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006161 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006162 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006163 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006164 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006165 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006166 } else {
6167 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6168 goto cleanup;
6169 }
Michal Vaskocf024702015-10-08 15:01:42 +02006170 }
Radek Krejci51093642016-03-29 10:14:59 +02006171
6172 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006173 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006174 }
6175
Michal Vasko90fc2a32016-08-24 15:58:58 +02006176 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006177 }
6178
Radek Krejci0b7704f2016-03-18 12:16:14 +01006179 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006180
Radek Krejci51093642016-03-29 10:14:59 +02006181cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006182 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006183 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006184
Radek Krejci46165822016-08-26 14:06:27 +02006185 if (result) {
6186 if (node->when_status & LYD_WHEN_TRUE) {
6187 *result = 1;
6188 } else {
6189 *result = 0;
6190 }
6191 }
6192
Radek Krejci51093642016-03-29 10:14:59 +02006193 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006194}
6195
Radek Krejcicbb473e2016-09-16 14:48:32 +02006196static int
6197check_leafref_features(struct lys_type *type)
6198{
6199 struct lys_node *iter;
6200 struct ly_set *src_parents, *trg_parents, *features;
6201 unsigned int i, j, size, x;
6202 int ret = EXIT_SUCCESS;
6203
6204 assert(type->parent);
6205
6206 src_parents = ly_set_new();
6207 trg_parents = ly_set_new();
6208 features = ly_set_new();
6209
6210 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006211 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006212 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6213 continue;
6214 }
6215 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6216 }
6217 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006218 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006219 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6220 continue;
6221 }
6222 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6223 }
6224
6225 /* compare the features used in if-feature statements in the rest of both
6226 * chains of parents. The set of features used for target must be a subset
6227 * of features used for the leafref. This is not a perfect, we should compare
6228 * the truth tables but it could require too much resources, so we simplify that */
6229 for (i = 0; i < src_parents->number; i++) {
6230 iter = src_parents->set.s[i]; /* shortcut */
6231 if (!iter->iffeature_size) {
6232 continue;
6233 }
6234 for (j = 0; j < iter->iffeature_size; j++) {
6235 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6236 for (; size; size--) {
6237 if (!iter->iffeature[j].features[size - 1]) {
6238 /* not yet resolved feature, postpone this check */
6239 ret = EXIT_FAILURE;
6240 goto cleanup;
6241 }
6242 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6243 }
6244 }
6245 }
6246 x = features->number;
6247 for (i = 0; i < trg_parents->number; i++) {
6248 iter = trg_parents->set.s[i]; /* shortcut */
6249 if (!iter->iffeature_size) {
6250 continue;
6251 }
6252 for (j = 0; j < iter->iffeature_size; j++) {
6253 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6254 for (; size; size--) {
6255 if (!iter->iffeature[j].features[size - 1]) {
6256 /* not yet resolved feature, postpone this check */
6257 ret = EXIT_FAILURE;
6258 goto cleanup;
6259 }
6260 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6261 /* the feature is not present in features set of target's parents chain */
6262 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006263 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006264 "Leafref is not conditional based on \"%s\" feature as its target.",
6265 iter->iffeature[j].features[size - 1]->name);
6266 ret = -1;
6267 goto cleanup;
6268 }
6269 }
6270 }
6271 }
6272
6273cleanup:
6274 ly_set_free(features);
6275 ly_set_free(src_parents);
6276 ly_set_free(trg_parents);
6277
6278 return ret;
6279}
6280
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006281/**
Michal Vaskobb211122015-08-19 14:03:11 +02006282 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006283 *
6284 * @param[in] mod Main module.
6285 * @param[in] item Item to resolve. Type determined by \p type.
6286 * @param[in] type Type of the unresolved item.
6287 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006288 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006289 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006290 *
6291 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6292 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006293static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006294resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006295 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006296{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006297 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006298 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006299 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006300 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006301 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006302 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006303
Radek Krejcic79c6b12016-07-26 15:11:49 +02006304 struct ly_set *refs, *procs;
6305 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006306 struct lys_ident *ident;
6307 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006308 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006309 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006310 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006311 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006312 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006313 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006314 struct lys_ext_instance *ext, **extlist;
6315 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006316
6317 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006318 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006319 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006320 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006321 ident = item;
6322
Radek Krejci018f1f52016-08-03 16:01:20 +02006323 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006324 break;
6325 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006326 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006327 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006328 stype = item;
6329
Radek Krejci018f1f52016-08-03 16:01:20 +02006330 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006331 break;
6332 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006333 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006334 stype = item;
6335
Michal Vasko1c007172017-03-10 10:20:44 +01006336 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6337 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006338 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006339 /* check if leafref and its target are under a common if-features */
6340 rc = check_leafref_features(stype);
6341 if (rc) {
6342 break;
6343 }
6344
Michal Vaskobb520442017-05-23 10:55:18 +02006345 if (lys_node_module(node)->implemented) {
6346 /* make all the modules on the path implemented */
6347 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6348 if (!lys_node_module(next)->implemented) {
6349 if (lys_set_implemented(lys_node_module(next))) {
6350 rc = -1;
6351 break;
6352 }
6353 }
6354 }
6355 if (next) {
6356 break;
6357 }
6358
6359 /* store the backlink from leafref target */
6360 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6361 rc = -1;
6362 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006363 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006364 }
6365
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006366 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006367 case UNRES_TYPE_DER_EXT:
6368 parent_type++;
6369 /* no break */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006370 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006371 parent_type++;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006372 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006373 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006374 /* parent */
6375 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006376 stype = item;
6377
Michal Vasko88c29542015-11-27 14:57:53 +01006378 /* HACK type->der is temporarily unparsed type statement */
6379 yin = (struct lyxml_elem *)stype->der;
6380 stype->der = NULL;
6381
Pavol Vicana0e4e672016-02-24 12:20:04 +01006382 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6383 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006384 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006385
6386 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006387 /* may try again later */
6388 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006389 } else {
6390 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006391 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006392 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006393 }
6394
Michal Vasko88c29542015-11-27 14:57:53 +01006395 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006396 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006397 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006398 /* we need to always be able to free this, it's safe only in this case */
6399 lyxml_free(mod->ctx, yin);
6400 } else {
6401 /* may try again later, put all back how it was */
6402 stype->der = (struct lys_tpdf *)yin;
6403 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006404 }
Radek Krejcic13db382016-08-16 10:52:42 +02006405 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006406 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006407 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006408 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6409 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006410 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006411 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6412 * by uses statement until the type is resolved. We do that the same way as uses statements inside
Radek Krejci93def382017-05-24 15:33:48 +02006413 * grouping. The grouping cannot be used unless the unres counter is 0.
6414 * To remember that the grouping already increased the counter, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006415 * of the type's base member. */
6416 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6417 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006418 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6419 LOGERR(LY_EINT, "Too many unresolved items (type) inside a grouping.");
6420 return -1;
6421 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006422 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006423 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006424 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006425 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006426 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006427 iff_data = str_snode;
6428 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006429 if (!rc) {
6430 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006431 if (iff_data->infeature) {
6432 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6433 feat = *((struct lys_feature **)item);
6434 if (!feat->depfeatures) {
6435 feat->depfeatures = ly_set_new();
6436 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006437 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006438 }
6439 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006440 lydict_remove(mod->ctx, iff_data->fname);
6441 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006442 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006443 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006444 case UNRES_FEATURE:
6445 feat = (struct lys_feature *)item;
6446
6447 if (feat->iffeature_size) {
6448 refs = ly_set_new();
6449 procs = ly_set_new();
6450 ly_set_add(procs, feat, 0);
6451
6452 while (procs->number) {
6453 ref = procs->set.g[procs->number - 1];
6454 ly_set_rm_index(procs, procs->number - 1);
6455
6456 for (i = 0; i < ref->iffeature_size; i++) {
6457 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6458 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006459 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006460 if (ref->iffeature[i].features[j - 1] == feat) {
6461 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6462 goto featurecheckdone;
6463 }
6464
6465 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6466 k = refs->number;
6467 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6468 /* not yet seen feature, add it for processing */
6469 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6470 }
6471 }
6472 } else {
6473 /* forward reference */
6474 rc = EXIT_FAILURE;
6475 goto featurecheckdone;
6476 }
6477 }
6478
6479 }
6480 }
6481 rc = EXIT_SUCCESS;
6482
6483featurecheckdone:
6484 ly_set_free(refs);
6485 ly_set_free(procs);
6486 }
6487
6488 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006489 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006490 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006491 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006492 case UNRES_TYPEDEF_DFLT:
6493 parent_type++;
6494 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006495 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006496 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006497 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006498 break;
6499 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006500 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006501 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006502 choic = item;
6503
Radek Krejcie00d2312016-08-12 15:27:49 +02006504 if (!choic->dflt) {
6505 choic->dflt = resolve_choice_dflt(choic, expr);
6506 }
Michal Vasko7955b362015-09-04 14:18:15 +02006507 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006508 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006509 } else {
6510 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006511 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006512 break;
6513 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006514 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006515 break;
6516 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006517 unique_info = (struct unres_list_uniq *)item;
6518 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006519 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006520 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006521 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006522 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006523 case UNRES_XPATH:
6524 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006525 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006526 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006527 case UNRES_EXT:
6528 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006529 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006530 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006531 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006532 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006533 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006534 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006535 if (eplugin) {
6536 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006537 u = malloc(sizeof *u);
6538 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006539 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6540 /* something really bad happend since the extension finalization is not actually
6541 * being resolved while adding into unres, so something more serious with the unres
6542 * list itself must happened */
6543 return -1;
6544 }
Radek Krejci80056d52017-01-05 13:13:33 +01006545 }
6546 }
Radek Krejci79685c92017-02-17 10:49:43 +01006547 }
6548 if (!rc || rc == -1) {
6549 /* cleanup on success or fatal error */
6550 if (ext_data->datatype == LYS_IN_YIN) {
6551 /* YIN */
6552 lyxml_free(mod->ctx, ext_data->data.yin);
6553 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006554 /* YANG */
6555 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006556 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006557 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006558 }
6559 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006560 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006561 u = (uint8_t *)str_snode;
6562 ext = (*(struct lys_ext_instance ***)item)[*u];
6563 free(u);
6564
Radek Krejci80056d52017-01-05 13:13:33 +01006565 eplugin = ext->def->plugin;
6566
6567 /* inherit */
6568 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6569 root = (struct lys_node *)ext->parent;
6570 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6571 LY_TREE_DFS_BEGIN(root->child, next, node) {
6572 /* first, check if the node already contain instance of the same extension,
6573 * in such a case we won't inherit. In case the node was actually defined as
6574 * augment data, we are supposed to check the same way also the augment node itself */
6575 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6576 goto inherit_dfs_sibling;
6577 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6578 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6579 goto inherit_dfs_sibling;
6580 }
6581
6582 if (eplugin->check_inherit) {
6583 /* we have a callback to check the inheritance, use it */
6584 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6585 case 0:
6586 /* yes - continue with the inheriting code */
6587 break;
6588 case 1:
6589 /* no - continue with the node's sibling */
6590 goto inherit_dfs_sibling;
6591 case 2:
6592 /* no, but continue with the children, just skip the inheriting code for this node */
6593 goto inherit_dfs_child;
6594 default:
6595 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6596 ext->def->module->name, ext->def->name, rc);
6597 }
6598 }
6599
6600 /* inherit the extension */
6601 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
6602 if (!extlist) {
6603 LOGMEM;
6604 return -1;
6605 }
6606 extlist[node->ext_size] = malloc(sizeof **extlist);
6607 if (!extlist[node->ext_size]) {
6608 LOGMEM;
6609 node->ext = extlist;
6610 return -1;
6611 }
6612 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6613 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6614
6615 node->ext = extlist;
6616 node->ext_size++;
6617
6618inherit_dfs_child:
6619 /* modification of - select element for the next run - children first */
6620 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6621 next = NULL;
6622 } else {
6623 next = node->child;
6624 }
6625 if (!next) {
6626inherit_dfs_sibling:
6627 /* no children, try siblings */
6628 next = node->next;
6629 }
6630 while (!next) {
6631 /* go to the parent */
6632 node = lys_parent(node);
6633
6634 /* we are done if we are back in the root (the starter's parent */
6635 if (node == root) {
6636 break;
6637 }
6638
6639 /* parent is already processed, go to its sibling */
6640 next = node->next;
6641 }
6642 }
6643 }
6644 }
6645
6646 /* final check */
6647 if (eplugin->check_result) {
6648 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006649 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006650 return -1;
6651 }
6652 }
6653
6654 rc = 0;
6655 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006656 default:
6657 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006658 break;
6659 }
6660
Radek Krejci54081ce2016-08-12 15:21:47 +02006661 if (has_str && !rc) {
6662 /* the string is no more needed in case of success.
6663 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006664 lydict_remove(mod->ctx, str_snode);
6665 }
6666
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006667 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006668}
6669
Michal Vaskof02e3742015-08-05 16:27:02 +02006670/* logs directly */
6671static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006672print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006673{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006674 struct lyxml_elem *xml;
6675 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006676 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006677 const char *name = NULL;
6678 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006679
Michal Vaskof02e3742015-08-05 16:27:02 +02006680 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006681 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006682 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006683 break;
6684 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006685 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006686 break;
6687 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006688 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6689 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006690 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006691 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006692 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006693 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006694 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6695 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006696 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006697 } else {
6698 LY_TREE_FOR(xml->attr, attr) {
6699 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006700 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006701 break;
6702 }
6703 }
6704 assert(attr);
6705 }
Radek Krejcie534c132016-11-23 13:32:31 +01006706 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006707 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006708 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006709 iff_data = str_node;
6710 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006711 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006712 case UNRES_FEATURE:
6713 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6714 ((struct lys_feature *)item)->name);
6715 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006716 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006717 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006718 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006719 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006720 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006721 if (str_node) {
6722 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6723 } /* else no default value in the type itself, but we are checking some restrictions against
6724 * possible default value of some base type. The failure is caused by not resolved base type,
6725 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006726 break;
6727 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006728 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006729 break;
6730 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006731 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006732 break;
6733 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006734 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006735 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006736 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006737 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6738 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006739 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006740 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006741 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6742 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006743 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006744 case UNRES_EXT:
6745 extinfo = (struct unres_ext *)str_node;
6746 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6747 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6748 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006749 default:
6750 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006751 break;
6752 }
6753}
6754
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006755/**
Michal Vaskobb211122015-08-19 14:03:11 +02006756 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006757 *
6758 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006759 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006760 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006761 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006762 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006763int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006764resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006765{
Radek Krejci010e54b2016-03-15 09:40:34 +01006766 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006767 struct lyxml_elem *yin;
6768 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006769 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006770
6771 assert(unres);
6772
Michal Vaskoe8734262016-09-29 14:12:06 +02006773 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006774 if (*ly_vlog_hide_location()) {
6775 log_hidden = 1;
6776 } else {
6777 log_hidden = 0;
6778 ly_vlog_hide(1);
6779 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006780
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006781 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006782 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006783 unres_count = 0;
6784 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006785
6786 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006787 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006788 * if-features are resolved here to make sure that we will have all if-features for
6789 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006790 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006791 continue;
6792 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006793 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006794 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006795
Michal Vasko88c29542015-11-27 14:57:53 +01006796 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006797 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006798 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006799 unres->type[i] = UNRES_RESOLVED;
6800 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006801 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006802 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006803 if (!log_hidden) {
6804 ly_vlog_hide(0);
6805 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006806 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006807 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006808 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006809 } else {
6810 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006811 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006812 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006813 }
Michal Vasko88c29542015-11-27 14:57:53 +01006814 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006815
Michal Vasko88c29542015-11-27 14:57:53 +01006816 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006817 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006818 if (!log_hidden) {
6819 ly_vlog_hide(0);
6820 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006821
6822 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006823 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006824 continue;
6825 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006826 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejci63fc0962017-02-15 13:20:18 +01006827 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006828 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6829 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6830 yang =(struct yang_type *)yin;
6831 ((struct lys_type *)unres->item[i])->base = yang->base;
6832 if (yang->base == LY_TYPE_UNION) {
6833 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6834 }
6835 lydict_remove(mod->ctx, yang->name);
6836 free(yang);
6837 } else {
6838 lyxml_free(mod->ctx, yin);
6839 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006840 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006841 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006842 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006843 }
6844
Radek Krejci07d0fb92017-01-13 14:11:05 +01006845 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006846 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006847 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006848 continue;
6849 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006850
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006851 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006852 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006853 if (unres->type[i] == UNRES_LIST_UNIQ) {
6854 /* free the allocated structure */
6855 free(unres->item[i]);
6856 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006857 unres->type[i] = UNRES_RESOLVED;
6858 ++resolved;
6859 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006860 if (!log_hidden) {
6861 ly_vlog_hide(0);
6862 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006863 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006864 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006865 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006866 } else {
6867 /* forward reference, erase ly_errno */
6868 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006869 }
6870 }
6871
Michal Vasko74a60c02017-03-08 10:19:48 +01006872 if (!log_hidden) {
6873 ly_vlog_hide(0);
6874 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006875
Radek Krejci80056d52017-01-05 13:13:33 +01006876 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6877 for (i = 0; i < unres->count; ++i) {
6878 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6879 continue;
6880 }
6881
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006882 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci791f6c72017-02-22 15:23:39 +01006883 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006884 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006885 ++resolved;
6886 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006887 /* else error - it was already printed, but resolved was not increased,
6888 so this unres item will not be resolved again in the following code,
6889 but it will cause returning -1 at the end, this way we are able to
6890 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006891 }
6892
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006893 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006894 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6895 * all the validation errors
6896 */
6897 for (i = 0; i < unres->count; ++i) {
6898 if (unres->type[i] == UNRES_RESOLVED) {
6899 continue;
6900 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006901 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006902 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006903 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006904 unres->type[i] = UNRES_RESOLVED;
6905 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006906 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006907 }
Radek Krejcib3142312016-11-09 11:04:12 +01006908 if (resolved < unres->count) {
6909 return -1;
6910 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006911 }
6912
Michal Vaskoe8734262016-09-29 14:12:06 +02006913 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006914 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006915 return EXIT_SUCCESS;
6916}
6917
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006918/**
Michal Vaskobb211122015-08-19 14:03:11 +02006919 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006920 *
6921 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006922 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006923 * @param[in] item Item to resolve. Type determined by \p type.
6924 * @param[in] type Type of the unresolved item.
6925 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006926 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006927 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006928 */
6929int
Radek Krejci48464ed2016-03-17 15:44:09 +01006930unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6931 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006932{
Radek Krejci54081ce2016-08-12 15:21:47 +02006933 int rc;
6934 const char *dictstr;
6935
6936 dictstr = lydict_insert(mod->ctx, str, 0);
6937 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6938
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006939 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006940 lydict_remove(mod->ctx, dictstr);
6941 }
6942 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006943}
6944
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006945/**
Michal Vaskobb211122015-08-19 14:03:11 +02006946 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006947 *
6948 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006949 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006950 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006951 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006952 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006953 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006954 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6955 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006956 */
6957int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006958unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006959 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006960{
Michal Vaskoef486d72016-09-27 12:10:44 +02006961 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006962 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006963
Michal Vasko9bf425b2015-10-22 11:42:03 +02006964 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6965 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006966
Michal Vasko9e862e82017-03-08 10:20:49 +01006967#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006968 uint32_t u;
6969
Radek Krejci850a5de2016-11-08 14:06:40 +01006970 /* check for duplicities in unres */
6971 for (u = 0; u < unres->count; u++) {
6972 if (unres->type[u] == type && unres->item[u] == item &&
6973 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006974 /* duplication, should not happen */
6975 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006976 }
6977 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006978#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006979
Radek Krejcic293bac2017-02-27 11:25:28 +01006980 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01006981 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01006982 rc = EXIT_FAILURE;
6983 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01006984 if (*ly_vlog_hide_location()) {
6985 log_hidden = 1;
6986 } else {
6987 log_hidden = 0;
6988 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006989 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006990 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006991 if (!log_hidden) {
6992 ly_vlog_hide(0);
6993 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006994
Radek Krejci80056d52017-01-05 13:13:33 +01006995 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02006996 if (rc == -1) {
Radek Krejci80056d52017-01-05 13:13:33 +01006997 ly_err_repeat();
6998 }
6999 if (type == UNRES_LIST_UNIQ) {
7000 /* free the allocated structure */
7001 free(item);
7002 } else if (rc == -1 && type == UNRES_IFFEAT) {
7003 /* free the allocated resources */
7004 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007005 }
Radek Krejci80056d52017-01-05 13:13:33 +01007006 return rc;
7007 } else {
7008 /* erase info about validation errors */
7009 ly_err_clean(1);
7010 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007011
Radek Krejci80056d52017-01-05 13:13:33 +01007012 print_unres_schema_item_fail(item, type, snode);
7013
7014 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7015 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7016 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7017 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7018 lyxml_unlink_elem(mod->ctx, yin, 1);
7019 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7020 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007021 }
Michal Vasko88c29542015-11-27 14:57:53 +01007022 }
7023
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007024 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007025 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
7026 if (!unres->item) {
7027 LOGMEM;
7028 return -1;
7029 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007030 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007031 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
7032 if (!unres->type) {
7033 LOGMEM;
7034 return -1;
7035 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007036 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007037 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
7038 if (!unres->str_snode) {
7039 LOGMEM;
7040 return -1;
7041 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007042 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007043 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
7044 if (!unres->module) {
7045 LOGMEM;
7046 return -1;
7047 }
7048 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007049
Michal Vasko3767fb22016-07-21 12:10:57 +02007050 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007051}
7052
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007053/**
Michal Vaskobb211122015-08-19 14:03:11 +02007054 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007055 *
7056 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007057 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007058 * @param[in] item Old item to be resolved.
7059 * @param[in] type Type of the old unresolved item.
7060 * @param[in] new_item New item to use in the duplicate.
7061 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007062 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007063 */
Michal Vaskodad19402015-08-06 09:51:53 +02007064int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007065unres_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 +02007066{
7067 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007068 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007069 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007070
Michal Vaskocf024702015-10-08 15:01:42 +02007071 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007072
Radek Krejcid09d1a52016-08-11 14:05:45 +02007073 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7074 if (type == UNRES_LIST_UNIQ) {
7075 aux_uniq.list = item;
7076 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7077 item = &aux_uniq;
7078 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007079 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007080
7081 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007082 if (type == UNRES_LIST_UNIQ) {
7083 free(new_item);
7084 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007085 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007086 }
7087
Radek Krejcic79c6b12016-07-26 15:11:49 +02007088 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007089 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007090 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007091 LOGINT;
7092 return -1;
7093 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007094 } else if (type == UNRES_IFFEAT) {
7095 /* duplicate unres_iffeature_data */
7096 iff_data = malloc(sizeof *iff_data);
7097 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7098 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7099 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7100 LOGINT;
7101 return -1;
7102 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007103 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007104 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007105 LOGINT;
7106 return -1;
7107 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007108 }
Michal Vaskodad19402015-08-06 09:51:53 +02007109
7110 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007111}
7112
Michal Vaskof02e3742015-08-05 16:27:02 +02007113/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007114int
Michal Vasko878e38d2016-09-05 12:17:53 +02007115unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007116{
Michal Vasko878e38d2016-09-05 12:17:53 +02007117 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007118 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007119
Radek Krejciddddd0d2017-01-20 15:20:46 +01007120 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007121 i = start_on_backwards;
7122 } else {
7123 i = unres->count - 1;
7124 }
7125 for (; i > -1; i--) {
7126 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007127 continue;
7128 }
7129 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007130 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007131 break;
7132 }
7133 } else {
7134 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7135 aux_uniq2 = (struct unres_list_uniq *)item;
7136 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007137 break;
7138 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007139 }
7140 }
7141
Michal Vasko878e38d2016-09-05 12:17:53 +02007142 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007143}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007144
Michal Vaskoede9c472016-06-07 09:38:15 +02007145static void
7146unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7147{
7148 struct lyxml_elem *yin;
7149 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007150 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007151
7152 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007153 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007154 case UNRES_TYPE_DER:
7155 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7156 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7157 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007158 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007159 lydict_remove(ctx, yang->name);
7160 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007161 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7162 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7163 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007164 } else {
7165 lyxml_free(ctx, yin);
7166 }
7167 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007168 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007169 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7170 lydict_remove(ctx, iff_data->fname);
7171 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007172 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007173 case UNRES_IDENT:
7174 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007175 case UNRES_CHOICE_DFLT:
7176 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007177 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7178 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007179 case UNRES_LIST_UNIQ:
7180 free(unres->item[i]);
7181 break;
PavolVicanc1807262017-01-31 18:00:27 +01007182 case UNRES_EXT:
7183 free(unres->str_snode[i]);
7184 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007185 default:
7186 break;
7187 }
7188 unres->type[i] = UNRES_RESOLVED;
7189}
7190
Michal Vasko88c29542015-11-27 14:57:53 +01007191void
Michal Vasko44ab1462017-05-18 13:18:36 +02007192unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007193{
7194 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007195 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007196
Radek Krejcic071c542016-01-27 14:57:51 +01007197 if (!unres || !(*unres)) {
7198 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007199 }
7200
Michal Vasko44ab1462017-05-18 13:18:36 +02007201 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007202
7203 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007204 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007205 if ((*unres)->type[i] != UNRES_RESOLVED) {
7206 unresolved++;
7207 }
7208 continue;
7209 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007210
7211 /* free heap memory for the specific item */
7212 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007213 }
7214
Michal Vaskoede9c472016-06-07 09:38:15 +02007215 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007216 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007217 free((*unres)->item);
7218 free((*unres)->type);
7219 free((*unres)->str_snode);
7220 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007221 free((*unres));
7222 (*unres) = NULL;
7223 }
Michal Vasko88c29542015-11-27 14:57:53 +01007224}
7225
Michal Vasko3cfa3182017-01-17 10:00:58 +01007226static int
7227check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7228{
7229 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007230 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007231 char *buf;
7232
7233 for (op_node = lys_parent(sleaf);
7234 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7235 op_node = lys_parent(op_node));
7236
7237 if (op_node && lys_parent(op_node)) {
7238 /* nested operation - any absolute path is external */
7239 return 1;
7240 }
7241
7242 /* get the first node from the instid */
7243 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7244 if (!buf) {
7245 LOGMEM;
7246 return -1;
7247 }
7248
7249 /* there is a predicate, remove it */
7250 if (buf[strlen(buf) - 1] == ']') {
7251 assert(strchr(buf, '['));
7252 *strchr(buf, '[') = '\0';
7253 }
7254
7255 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01007256 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007257 if (!set || !set->number) {
7258 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007259 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007260 return 1;
7261 }
7262 free(buf);
7263
Michal Vasko3c777092017-01-17 14:10:09 +01007264 first_node = set->set.s[0];
7265 ly_set_free(set);
7266
Michal Vasko3cfa3182017-01-17 10:00:58 +01007267 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7268
7269 if (op_node) {
7270 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007271 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007272 assert(set->number == 1);
7273 return 0;
7274 } else {
7275 return 1;
7276 }
7277 }
7278
7279 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7280 * this itself), so we say it's not external */
7281 return 0;
7282}
7283
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007284/**
7285 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7286 *
7287 * @param[in] data Data node where the path is used
7288 * @param[in] path Instance-identifier node value.
7289 * @param[in,out] ret Resolved instance or NULL.
7290 *
7291 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7292 */
7293static int
7294resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7295{
7296 int i = 0, j;
7297 const struct lys_module *mod;
7298 struct ly_ctx *ctx = data->schema->module->ctx;
7299 const char *model, *name;
7300 char *str;
7301 int mod_len, name_len, has_predicate;
7302 struct unres_data node_match;
7303
7304 memset(&node_match, 0, sizeof node_match);
7305 *ret = NULL;
7306
7307 /* we need root to resolve absolute path */
7308 for (; data->parent; data = data->parent);
7309 /* we're still parsing it and the pointer is not correct yet */
7310 if (data->prev) {
7311 for (; data->prev->next; data = data->prev);
7312 }
7313
7314 /* search for the instance node */
7315 while (path[i]) {
7316 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7317 if (j <= 0) {
7318 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7319 goto error;
7320 }
7321 i += j;
7322
7323 str = strndup(model, mod_len);
7324 if (!str) {
7325 LOGMEM;
7326 goto error;
7327 }
7328 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007329 if (ctx->data_clb) {
7330 if (!mod) {
7331 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7332 } else if (!mod->implemented) {
7333 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7334 }
7335 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007336 free(str);
7337
Michal Vaskof53187d2017-01-13 13:23:14 +01007338 if (!mod || !mod->implemented || mod->disabled) {
7339 break;
7340 }
7341
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007342 if (resolve_data(mod, name, name_len, data, &node_match)) {
7343 /* no instance exists */
7344 break;
7345 }
7346
7347 if (has_predicate) {
7348 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1c007172017-03-10 10:20:44 +01007349 j = resolve_instid_predicate(&path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007350 if (j < 1) {
7351 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7352 goto error;
7353 }
7354 i += j;
7355
7356 if (!node_match.count) {
7357 /* no instance exists */
7358 break;
7359 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007360 } else if (node_match.count) {
7361 /* check that we are not addressing lists */
7362 for (j = 0; (unsigned)j < node_match.count; ++j) {
7363 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7364 unres_data_del(&node_match, j--);
7365 }
7366 }
7367 if (!node_match.count) {
7368 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7369 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007370 }
7371 }
7372
7373 if (!node_match.count) {
7374 /* no instance exists */
7375 if (req_inst > -1) {
7376 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7377 return EXIT_FAILURE;
7378 }
7379 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7380 return EXIT_SUCCESS;
7381 } else if (node_match.count > 1) {
7382 /* instance identifier must resolve to a single node */
7383 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7384 goto error;
7385 } else {
7386 /* we have required result, remember it and cleanup */
7387 *ret = node_match.node[0];
7388 free(node_match.node);
7389 return EXIT_SUCCESS;
7390 }
7391
7392error:
7393 /* cleanup */
7394 free(node_match.node);
7395 return -1;
7396}
7397
7398static int
7399resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007400{
Radek Krejci7de36cf2016-09-12 16:18:50 +02007401 struct unres_data matches;
7402 uint32_t i;
7403
Radek Krejci9b6aad22016-09-20 15:55:51 +02007404 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007405 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007406 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007407
7408 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007409 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007410 return -1;
7411 }
7412
7413 /* check that value matches */
7414 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007415 /* not that the value is already in canonical form since the parsers does the conversion,
7416 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007417 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007418 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007419 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007420 break;
7421 }
7422 }
7423
7424 free(matches.node);
7425
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007426 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007427 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007428 if (req_inst > -1) {
7429 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007430 return EXIT_FAILURE;
7431 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007432 LOGVRB("There is no leafref \"%s\" with the value \"%s\", but it is not required.", path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007433 }
7434 }
7435
7436 return EXIT_SUCCESS;
7437}
7438
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007439/* ignore fail because we are parsing edit-config, get, or get-config - but only if the union includes leafref or instid */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007440int
7441resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7442 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007443{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007444 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007445 struct lyd_node *ret;
7446 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007447 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007448
7449 assert(type->base == LY_TYPE_UNION);
7450
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007451 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7452 /* either NULL or instid previously converted to JSON */
7453 json_val = leaf->value.string;
7454 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007455
Michal Vaskofd6c6502017-01-06 12:15:41 +01007456 if (store) {
7457 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7458 free(leaf->value.bit);
7459 }
7460 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007461 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007462
7463 /* turn logging off, we are going to try to validate the value with all the types in order */
7464 hidden = *ly_vlog_hide_location();
7465 ly_vlog_hide(1);
7466
7467 t = NULL;
7468 found = 0;
7469 while ((t = lyp_get_next_union_type(type, t, &found))) {
7470 found = 0;
7471
7472 switch (t->base) {
7473 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007474 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7475 req_inst = -1;
7476 } else {
7477 req_inst = t->info.lref.req;
7478 }
7479
7480 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007481 if (store) {
7482 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7483 /* valid resolved */
7484 leaf->value.leafref = ret;
7485 leaf->value_type = LY_TYPE_LEAFREF;
7486 } else {
7487 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007488 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007489 return -1;
7490 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007491 }
7492 }
7493
7494 success = 1;
7495 }
7496 break;
7497 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007498 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7499 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7500 req_inst = -1;
7501 } else {
7502 req_inst = t->info.inst.req;
7503 }
7504
Michal Vaskod3a03112017-01-23 09:56:02 +01007505 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007506 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007507 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007508 /* valid resolved */
7509 leaf->value.instance = ret;
7510 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007511
Michal Vaskofd6c6502017-01-06 12:15:41 +01007512 if (json_val) {
7513 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7514 leaf->value_str = json_val;
7515 json_val = NULL;
7516 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007517 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007518 /* valid unresolved */
7519 if (json_val) {
7520 /* put the JSON val back */
7521 leaf->value.string = json_val;
7522 json_val = NULL;
7523 } else {
7524 leaf->value.instance = NULL;
7525 }
7526 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007527 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007528 }
7529
7530 success = 1;
7531 }
7532 break;
7533 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007534 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007535 success = 1;
7536 }
7537 break;
7538 }
7539
7540 if (success) {
7541 break;
7542 }
7543
7544 /* erase information about errors - they are false or irrelevant
7545 * and will be replaced by a single error messages */
7546 ly_err_clean(1);
7547
7548 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007549 if (store) {
7550 if (t->base == LY_TYPE_BITS) {
7551 free(leaf->value.bit);
7552 }
7553 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007554 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007555 }
7556
7557 /* turn logging back on */
7558 if (!hidden) {
7559 ly_vlog_hide(0);
7560 }
7561
7562 if (json_val) {
7563 if (!success) {
7564 /* put the value back for now */
7565 assert(leaf->value_type == LY_TYPE_UNION);
7566 leaf->value.string = json_val;
7567 } else {
7568 /* value was ultimately useless, but we could not have known */
7569 lydict_remove(leaf->schema->module->ctx, json_val);
7570 }
7571 }
7572
Michal Vaskofd6c6502017-01-06 12:15:41 +01007573 if (success) {
7574 if (resolved_type) {
7575 *resolved_type = t;
7576 }
7577 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007578 /* not found and it is required */
7579 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007580 return EXIT_FAILURE;
7581 }
7582
7583 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007584
Radek Krejci9b6aad22016-09-20 15:55:51 +02007585}
7586
Michal Vasko8bcdf292015-08-19 14:04:43 +02007587/**
7588 * @brief Resolve a single unres data item. Logs directly.
7589 *
Michal Vaskocf024702015-10-08 15:01:42 +02007590 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007591 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007592 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007593 *
7594 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7595 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007596int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007597resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007598{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007599 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007600 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007601 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007602 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007603
Michal Vasko83a6c462015-10-08 16:43:53 +02007604 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007605 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007606
Michal Vaskocf024702015-10-08 15:01:42 +02007607 switch (type) {
7608 case UNRES_LEAFREF:
7609 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007610 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007611 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7612 req_inst = -1;
7613 } else {
7614 req_inst = sleaf->type.info.lref.req;
7615 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007616 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7617 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007618 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007619 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007620 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7621 free(leaf->value.bit);
7622 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007623 leaf->value.leafref = ret;
7624 leaf->value_type = LY_TYPE_LEAFREF;
7625 } else {
7626 /* valid unresolved */
7627 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007628 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007629 return -1;
7630 }
7631 }
7632 }
7633 leaf->validity &= ~LYD_VAL_LEAFREF;
7634 } else {
7635 return rc;
7636 }
7637 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007638
Michal Vaskocf024702015-10-08 15:01:42 +02007639 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007640 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007641 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7642 if (ext_dep == -1) {
7643 return -1;
7644 }
7645
7646 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7647 req_inst = -1;
7648 } else {
7649 req_inst = sleaf->type.info.inst.req;
7650 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007651 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7652 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007653 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007654 /* valid resolved */
7655 leaf->value.instance = ret;
7656 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007657 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007658 /* valid unresolved */
7659 leaf->value.instance = NULL;
7660 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007661 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007662 } else {
7663 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007664 }
Michal Vaskocf024702015-10-08 15:01:42 +02007665 break;
7666
Radek Krejci7de36cf2016-09-12 16:18:50 +02007667 case UNRES_UNION:
7668 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007669 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007670
Michal Vaskocf024702015-10-08 15:01:42 +02007671 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007672 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007673 return rc;
7674 }
7675 break;
7676
Michal Vaskobf19d252015-10-08 15:39:17 +02007677 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007678 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007679 return rc;
7680 }
7681 break;
7682
7683 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007684 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007685 return rc;
7686 }
7687 break;
7688
Michal Vaskocf024702015-10-08 15:01:42 +02007689 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007690 LOGINT;
7691 return -1;
7692 }
7693
7694 return EXIT_SUCCESS;
7695}
7696
7697/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007698 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007699 *
7700 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007701 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007702 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007703 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007704 */
7705int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007706unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007707{
Radek Krejci03b71f72016-03-16 11:10:09 +01007708 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007709 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007710 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007711
Radek Krejci03b71f72016-03-16 11:10:09 +01007712 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007713 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7714 if (!unres->node) {
7715 LOGMEM;
7716 return -1;
7717 }
Michal Vaskocf024702015-10-08 15:01:42 +02007718 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007719 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7720 if (!unres->type) {
7721 LOGMEM;
7722 return -1;
7723 }
Michal Vaskocf024702015-10-08 15:01:42 +02007724 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007725
Radek Krejci0b7704f2016-03-18 12:16:14 +01007726 if (type == UNRES_WHEN) {
7727 /* remove previous result */
7728 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007729 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007730
7731 return EXIT_SUCCESS;
7732}
7733
7734/**
7735 * @brief Resolve every unres data item in the structure. Logs directly.
7736 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007737 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7738 * unresolved leafrefs/instids are accepted).
7739 *
7740 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7741 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007742 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007743 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7744 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007745 *
7746 * @return EXIT_SUCCESS on success, -1 on error.
7747 */
7748int
Radek Krejci082c84f2016-10-17 16:33:06 +02007749resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007750{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007751 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007752 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007753 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007754
Radek Krejci082c84f2016-10-17 16:33:06 +02007755 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007756 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007757
7758 if (!unres->count) {
7759 return EXIT_SUCCESS;
7760 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007761
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007762 if (options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007763 ignore_fail = 1;
7764 } else if (options & LYD_OPT_NOEXTDEPS) {
7765 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007766 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007767 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007768 }
7769
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007770 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007771 ly_vlog_hide(1);
7772
Radek Krejci0b7704f2016-03-18 12:16:14 +01007773 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007774 first = 1;
7775 stmt_count = 0;
7776 resolved = 0;
7777 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007778 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007779 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007780 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007781 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007782 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007783 continue;
7784 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007785 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007786 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007787 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007788 }
7789
7790 /* resolve when condition only when all parent when conditions are already resolved */
7791 for (parent = unres->node[i]->parent;
7792 parent && LYD_WHEN_DONE(parent->when_status);
7793 parent = parent->parent) {
7794 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7795 /* the parent node was already unlinked, do not resolve this node,
7796 * it will be removed anyway, so just mark it as resolved
7797 */
7798 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7799 unres->type[i] = UNRES_RESOLVED;
7800 resolved++;
7801 break;
7802 }
7803 }
7804 if (parent) {
7805 continue;
7806 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007807
Michal Vasko3cfa3182017-01-17 10:00:58 +01007808 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007809 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007810 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007811 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007812 /* false when condition */
7813 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007814 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007815 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007816 } /* follows else */
7817
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007818 /* auto-delete */
7819 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7820 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7821
Radek Krejci0c0086a2016-03-24 15:20:28 +01007822 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7823 /* if it has parent non-presence containers that would be empty, we should actually
7824 * remove the container
7825 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007826 for (parent = unres->node[i];
7827 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7828 parent = parent->parent) {
7829 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7830 /* presence container */
7831 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007832 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007833 if (parent->next || parent->prev != parent) {
7834 /* non empty (the child we are in and we are going to remove is not the only child) */
7835 break;
7836 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007837 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007838 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007839
Radek Krejci0c0086a2016-03-24 15:20:28 +01007840 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007841 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007842 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007843
Radek Krejci0b7704f2016-03-18 12:16:14 +01007844 lyd_unlink(unres->node[i]);
7845 unres->type[i] = UNRES_DELETE;
7846 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007847
7848 /* update the rest of unres items */
7849 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007850 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007851 continue;
7852 }
7853
7854 /* test if the node is in subtree to be deleted */
7855 for (parent = unres->node[j]; parent; parent = parent->parent) {
7856 if (parent == unres->node[i]) {
7857 /* yes, it is */
7858 unres->type[j] = UNRES_RESOLVED;
7859 resolved++;
7860 break;
7861 }
7862 }
7863 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007864 } else {
7865 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007866 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007867 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007868 resolved++;
7869 progress = 1;
7870 } else if (rc == -1) {
7871 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007872 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007873 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007874 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007875 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007876 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007877 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007878 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007879
Radek Krejci0b7704f2016-03-18 12:16:14 +01007880 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007881 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007882 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007883 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007884 return -1;
7885 }
7886
7887 for (i = 0; del_items && i < unres->count; i++) {
7888 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7889 if (unres->type[i] != UNRES_DELETE) {
7890 continue;
7891 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007892 if (!unres->node[i]) {
7893 unres->type[i] = UNRES_RESOLVED;
7894 del_items--;
7895 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007896 }
7897
7898 /* really remove the complete subtree */
7899 lyd_free(unres->node[i]);
7900 unres->type[i] = UNRES_RESOLVED;
7901 del_items--;
7902 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007903
7904 /* now leafrefs */
7905 first = 1;
7906 stmt_count = 0;
7907 resolved = 0;
7908 do {
7909 progress = 0;
7910 for (i = 0; i < unres->count; i++) {
7911 if (unres->type[i] != UNRES_LEAFREF) {
7912 continue;
7913 }
7914 if (first) {
7915 /* count leafref nodes in unres list */
7916 stmt_count++;
7917 }
7918
7919 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7920 if (!rc) {
7921 unres->type[i] = UNRES_RESOLVED;
7922 ly_err_clean(1);
7923 resolved++;
7924 progress = 1;
7925 } else if (rc == -1) {
7926 ly_vlog_hide(0);
7927 /* print only this last error */
7928 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7929 return -1;
7930 } /* else forward reference */
7931 }
7932 first = 0;
7933 } while (progress && resolved < stmt_count);
7934
7935 /* do we have some unresolved leafrefs? */
7936 if (stmt_count > resolved) {
7937 ly_vlog_hide(0);
7938 ly_err_repeat();
7939 return -1;
7940 }
7941
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007942 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007943
7944 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007945 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007946 if (unres->type[i] == UNRES_RESOLVED) {
7947 continue;
7948 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007949 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007950
Michal Vasko3cfa3182017-01-17 10:00:58 +01007951 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007952 if (rc) {
7953 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007954 return -1;
7955 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007956
7957 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007958 }
7959
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007960 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007961 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007962 return EXIT_SUCCESS;
7963}