blob: 7f27b3b6ff22c19a481d38aced87ad76df99f49a [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 */
1578static int
Michal Vaskodc300b02017-04-07 14:09:20 +02001579schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
1580 const char *mod_name, int mod_name_len, int implemented_mod,
1581 const struct lys_node **start_parent)
Radek Krejcibdf92362016-04-08 14:43:34 +02001582{
1583 const struct lys_module *prefix_mod;
1584
1585 /* module check */
1586 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001587 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001588 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001589 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001590 if (!prefix_mod) {
1591 return -1;
1592 }
1593 if (prefix_mod != lys_node_module(sibling)) {
1594 return 1;
1595 }
1596
Radek Krejcibdf92362016-04-08 14:43:34 +02001597 /* the result node? */
1598 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001599 return 0;
1600 }
1601
Michal Vaskodc300b02017-04-07 14:09:20 +02001602 /* move down the tree, if possible */
1603 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1604 return -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001605 }
Michal Vaskodc300b02017-04-07 14:09:20 +02001606 *start_parent = sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001607
1608 return 2;
1609}
1610
Radek Krejcidf46e222016-11-08 11:57:37 +01001611/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1612 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1613 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001614int
1615resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001616 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001617{
Radek Krejcidf46e222016-11-08 11:57:37 +01001618 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001619 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001620 int r, nam_len, mod_name_len, is_relative = -1;
1621 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001622 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001623
1624 assert(nodeid && (start || module) && !(start && module) && ret);
1625
1626 id = nodeid;
1627
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001628 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 +01001629 return ((id - nodeid) - r) + 1;
1630 }
1631 id += r;
1632
1633 if ((is_relative && !start) || (!is_relative && !module)) {
1634 return -1;
1635 }
1636
1637 /* descendant-schema-nodeid */
1638 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001639 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001640
Michal Vasko24476fa2017-03-08 12:33:48 +01001641 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001642
Michal Vasko3edeaf72016-02-11 13:17:43 +01001643 /* absolute-schema-nodeid */
1644 } else {
1645 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001646 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001647 /* if the submodule augments the mainmodule (or in general a module augments
1648 * itself, we don't want to search for the implemented module but augments
1649 * the module anyway. But when augmenting another module, we need the implemented
1650 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001651 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001652 if (!aux_mod->implemented && implement) {
1653 /* make the found module implemented */
1654 if (lys_set_implemented(aux_mod)) {
1655 return -1;
1656 }
1657 }
1658 start_mod = aux_mod;
1659 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001660 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001661 if (!start_mod) {
1662 return -1;
1663 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001664 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001665 }
1666
1667 while (1) {
1668 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001669 mod_name_prev = mod_name;
Michal Vasko24476fa2017-03-08 12:33:48 +01001670 while ((sibling = lys_getnext(sibling, start_parent, start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001671 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001672 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001673 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskodc300b02017-04-07 14:09:20 +02001674 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, implement, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001675 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001676 *ret = sibling;
1677 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001678 } else if (r == 1) {
1679 continue;
1680 } else if (r == 2) {
1681 break;
1682 } else {
1683 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001684 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001685 }
1686 }
1687
1688 /* no match */
1689 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001690 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001691 return EXIT_SUCCESS;
1692 }
1693
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001694 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 +01001695 return ((id - nodeid) - r) + 1;
1696 }
1697 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001698
1699 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1700 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1701 /* we are getting into another module (augment) */
1702 if (implement) {
1703 /* we have to check that also target modules are implemented, if not, we have to change it */
1704 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1705 if (!aux_mod) {
1706 return -1;
1707 }
1708 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001709 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001710 if (!aux_mod->implemented) {
1711 /* make the found module implemented */
1712 if (lys_set_implemented(aux_mod)) {
1713 return -1;
1714 }
1715 }
1716 }
1717 } else {
1718 /* we are not implementing the module itself, so the augments outside the module are ignored */
1719 *ret = NULL;
1720 return EXIT_SUCCESS;
1721 }
1722 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001723 }
1724
1725 /* cannot get here */
1726 LOGINT;
1727 return -1;
1728}
1729
Radek Krejcif3c71de2016-04-11 12:45:46 +02001730/* unique, refine,
1731 * >0 - unexpected char on position (ret - 1),
1732 * 0 - ok (but ret can still be NULL),
1733 * -1 - error,
1734 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735int
1736resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001737 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001738{
1739 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001740 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001741 int r, nam_len, mod_name_len, is_relative = -1;
1742 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001743 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001744
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001745 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001746 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001747
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001748 if (!start) {
1749 /* leaf not found */
1750 return 0;
1751 }
1752
Michal Vasko3edeaf72016-02-11 13:17:43 +01001753 id = nodeid;
1754 module = start->module;
1755
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001756 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 +01001757 return ((id - nodeid) - r) + 1;
1758 }
1759 id += r;
1760
1761 if (!is_relative) {
1762 return -1;
1763 }
1764
Michal Vasko24476fa2017-03-08 12:33:48 +01001765 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001766 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001767 start_parent = lys_parent(start_parent);
1768 }
1769
Michal Vasko3edeaf72016-02-11 13:17:43 +01001770 while (1) {
1771 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001772 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001773 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001774 /* name match */
1775 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskodc300b02017-04-07 14:09:20 +02001776 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, 0, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001777 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001778 if (!(sibling->nodetype & ret_nodetype)) {
1779 /* wrong node type, too bad */
1780 continue;
1781 }
1782 *ret = sibling;
1783 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001784 } else if (r == 1) {
1785 continue;
1786 } else if (r == 2) {
1787 break;
1788 } else {
1789 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001790 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001791 }
1792 }
1793
1794 /* no match */
1795 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001796 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001797 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001798 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1799 *ret = NULL;
1800 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001801 }
1802
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001803 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 +01001804 return ((id - nodeid) - r) + 1;
1805 }
1806 id += r;
1807 }
1808
1809 /* cannot get here */
1810 LOGINT;
1811 return -1;
1812}
1813
1814/* choice default */
1815int
1816resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1817{
1818 /* cannot actually be a path */
1819 if (strchr(nodeid, '/')) {
1820 return -1;
1821 }
1822
Michal Vaskodc300b02017-04-07 14:09:20 +02001823 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001824}
1825
1826/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1827static int
1828resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1829{
1830 const struct lys_module *module;
1831 const char *mod_prefix, *name;
1832 int i, mod_prefix_len, nam_len;
1833
1834 /* parse the identifier, it must be parsed on one call */
1835 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1836 return -i + 1;
1837 }
1838
1839 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1840 if (!module) {
1841 return -1;
1842 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01001843 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001844 start = module->data;
1845 }
1846
1847 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1848
1849 return EXIT_SUCCESS;
1850}
1851
1852int
1853resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1854 const struct lys_node **ret)
1855{
1856 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001857 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001858 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001859 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001860
1861 assert(nodeid && module && ret);
1862 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1863
1864 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01001865 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001866
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001867 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 +01001868 return ((id - nodeid) - r) + 1;
1869 }
1870 id += r;
1871
1872 if (is_relative) {
1873 return -1;
1874 }
1875
1876 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001877 if (!abs_start_mod) {
1878 return -1;
1879 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001880
1881 while (1) {
1882 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001883 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01001884 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1885 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001886 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskodc300b02017-04-07 14:09:20 +02001887 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, 0, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001888 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001889 if (!(sibling->nodetype & ret_nodetype)) {
1890 /* wrong node type, too bad */
1891 continue;
1892 }
1893 *ret = sibling;
1894 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001895 } else if (r == 1) {
1896 continue;
1897 } else if (r == 2) {
1898 break;
1899 } else {
1900 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001901 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001902 }
1903 }
1904
1905 /* no match */
1906 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001907 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001908 return EXIT_SUCCESS;
1909 }
1910
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001911 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 +01001912 return ((id - nodeid) - r) + 1;
1913 }
1914 id += r;
1915 }
1916
1917 /* cannot get here */
1918 LOGINT;
1919 return -1;
1920}
1921
Michal Vaskoe733d682016-03-14 09:08:27 +01001922static int
Michal Vasko3547c532016-03-14 09:40:50 +01001923resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001924{
1925 const char *name;
1926 int nam_len, has_predicate, i;
1927
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001928 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1929 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001930 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001931 return -1;
1932 }
1933
1934 predicate += i;
1935 *parsed += i;
1936
Michal Vasko58c2aab2017-01-05 10:02:05 +01001937 if (!isdigit(name[0])) {
1938 for (i = 0; i < list->keys_size; ++i) {
1939 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1940 break;
1941 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001942 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001943
Michal Vasko58c2aab2017-01-05 10:02:05 +01001944 if (i == list->keys_size) {
1945 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1946 return -1;
1947 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001948 }
1949
1950 /* more predicates? */
1951 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001952 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001953 }
1954
1955 return 0;
1956}
1957
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001958/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001959const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001960resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001961{
Michal Vasko10728b52016-04-07 14:26:29 +02001962 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001963 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001964 const struct lys_node *sibling, *start_parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02001965 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001966 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001967 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001968
Michal Vasko3547c532016-03-14 09:40:50 +01001969 assert(nodeid && (ctx || start));
1970 if (!ctx) {
1971 ctx = start->module->ctx;
1972 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001973
1974 id = nodeid;
1975
Michal Vaskoe733d682016-03-14 09:08:27 +01001976 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 +01001977 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001978 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001979 }
1980 id += r;
1981
1982 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001983 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001984 start_parent = start;
1985 while (start_parent && (start_parent->nodetype == LYS_USES)) {
1986 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01001987 }
1988 module = start->module;
1989 } else {
1990 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001991 str = strndup(nodeid, (name + nam_len) - nodeid);
1992 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1993 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001994 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001995 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1996 LOGINT;
1997 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001998 }
1999
Michal Vasko971a3ca2016-04-01 13:09:29 +02002000 if (ly_buf_used && module_name[0]) {
2001 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2002 }
2003 ly_buf_used++;
2004
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002005 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002006 module_name[mod_name_len] = '\0';
2007 module = ly_ctx_get_module(ctx, module_name, NULL);
2008
2009 if (buf_backup) {
2010 /* return previous internal buffer content */
2011 strcpy(module_name, buf_backup);
2012 free(buf_backup);
2013 buf_backup = NULL;
2014 }
2015 ly_buf_used--;
2016
Michal Vasko3547c532016-03-14 09:40:50 +01002017 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002018 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2019 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2020 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002021 return NULL;
2022 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002023 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002024
2025 /* now it's as if there was no module name */
2026 mod_name = NULL;
2027 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002028 }
2029
Michal Vaskoe733d682016-03-14 09:08:27 +01002030 prev_mod = module;
2031
Michal Vasko3edeaf72016-02-11 13:17:43 +01002032 while (1) {
2033 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002034 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002035 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002036 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002037 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002038 /* module check */
2039 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002040 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002041 LOGINT;
2042 return NULL;
2043 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002044
2045 if (ly_buf_used && module_name[0]) {
2046 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2047 }
2048 ly_buf_used++;
2049
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002050 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002051 module_name[mod_name_len] = '\0';
2052 /* will also find an augment module */
2053 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002054
2055 if (buf_backup) {
2056 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002057 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002058 free(buf_backup);
2059 buf_backup = NULL;
2060 }
2061 ly_buf_used--;
2062
Michal Vasko3edeaf72016-02-11 13:17:43 +01002063 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002064 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2065 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2066 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002067 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002068 }
2069 } else {
2070 prefix_mod = prev_mod;
2071 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002072 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002073 continue;
2074 }
2075
Michal Vaskoe733d682016-03-14 09:08:27 +01002076 /* do we have some predicates on it? */
2077 if (has_predicate) {
2078 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002079 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2080 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2081 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2082 return NULL;
2083 }
2084 } else if (sibling->nodetype == LYS_LIST) {
2085 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2086 return NULL;
2087 }
2088 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002089 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002090 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002091 }
2092 id += r;
2093 }
2094
Michal Vasko3edeaf72016-02-11 13:17:43 +01002095 /* the result node? */
2096 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002097 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002098 }
2099
Michal Vaskodc300b02017-04-07 14:09:20 +02002100 /* move down the tree, if possible */
2101 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2102 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2103 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002104 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002105 start_parent = sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002106
2107 /* update prev mod */
Michal Vaskod09a5022017-03-08 13:14:40 +01002108 prev_mod = (start_parent ? start_parent->child->module : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002109 break;
2110 }
2111 }
2112
2113 /* no match */
2114 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002115 str = strndup(nodeid, (name + nam_len) - nodeid);
2116 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2117 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002118 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002119 }
2120
Michal Vaskoe733d682016-03-14 09:08:27 +01002121 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 +01002122 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002123 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002124 }
2125 id += r;
2126 }
2127
2128 /* cannot get here */
2129 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002130 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002131}
2132
Michal Vasko22448d32016-03-16 13:17:29 +01002133static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002134resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2135 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002136{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002137 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002138 int nam_len, val_len, has_predicate = 1, r;
2139 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002140 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002141
Radek Krejci61a86c62016-03-24 11:06:44 +01002142 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002143 assert(node->schema->nodetype == LYS_LIST);
2144
Michal Vasko53adfc72017-01-06 10:39:10 +01002145 /* is the predicate a number? */
2146 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2147 || !strncmp(name, ".", nam_len)) {
2148 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2149 return -1;
2150 }
2151
2152 if (isdigit(name[0])) {
2153 if (position == atoi(name)) {
2154 /* match */
2155 *parsed += r;
2156 return 0;
2157 } else {
2158 /* not a match */
2159 return 1;
2160 }
2161 }
2162
2163 if (!((struct lys_node_list *)node->schema)->keys_size) {
2164 /* no keys in schema - causes an error later */
2165 return 0;
2166 }
2167
Michal Vaskof29903d2016-04-18 13:13:10 +02002168 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002169 if (!key) {
2170 /* it is not a position, so we need a key for it to be a match */
2171 return 1;
2172 }
2173
2174 /* go through all the keys */
2175 i = 0;
2176 goto check_parsed_values;
2177
2178 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002179 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002180 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002181 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002182 }
2183
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002184 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2185 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002186 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002187 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002188 }
2189
Michal Vasko53adfc72017-01-06 10:39:10 +01002190check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002191 predicate += r;
2192 *parsed += r;
2193
Michal Vaskof29903d2016-04-18 13:13:10 +02002194 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002195 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002196 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002197 }
2198
Michal Vasko9ba34de2016-12-07 12:21:19 +01002199 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002200 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002201 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2202 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002203 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2204 } else {
2205 key_val = key->value_str;
2206 }
2207
Michal Vasko22448d32016-03-16 13:17:29 +01002208 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002209 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002210 return 1;
2211 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002212
2213 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002214 }
2215
2216 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002217 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002218 return -1;
2219 }
2220
2221 return 0;
2222}
2223
Radek Krejci45826012016-08-24 15:07:57 +02002224/**
2225 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2226 *
2227 * @param[in] nodeid Node data path to find
2228 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2229 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2230 * @param[out] parsed Number of characters processed in \p id
2231 * @return The closes parent (or the node itself) from the path
2232 */
Michal Vasko22448d32016-03-16 13:17:29 +01002233struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002234resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2235 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002236{
Michal Vasko10728b52016-04-07 14:26:29 +02002237 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002238 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002239 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002240 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002241 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002242 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002243 const struct lys_module *prefix_mod, *prev_mod;
2244 struct ly_ctx *ctx;
2245
2246 assert(nodeid && start && parsed);
2247
2248 ctx = start->schema->module->ctx;
2249 id = nodeid;
2250
2251 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 +01002252 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002253 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002254 return NULL;
2255 }
2256 id += r;
2257 /* add it to parsed only after the data node was actually found */
2258 last_parsed = r;
2259
2260 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002261 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002262 start = start->child;
2263 } else {
2264 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002265 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002266 }
2267
2268 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002269 list_instance_position = 0;
2270
Michal Vasko22448d32016-03-16 13:17:29 +01002271 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002272 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002273 if (lys_parent(sibling->schema)) {
2274 if (options & LYD_PATH_OPT_OUTPUT) {
2275 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002276 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002277 *parsed = -1;
2278 return NULL;
2279 }
2280 } else {
2281 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002282 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002283 *parsed = -1;
2284 return NULL;
2285 }
2286 }
2287 }
2288
Michal Vasko22448d32016-03-16 13:17:29 +01002289 /* name match */
2290 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2291
2292 /* module check */
2293 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002294 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002295 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002296 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002297 return NULL;
2298 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002299
2300 if (ly_buf_used && module_name[0]) {
2301 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2302 }
2303 ly_buf_used++;
2304
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002305 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002306 module_name[mod_name_len] = '\0';
2307 /* will also find an augment module */
2308 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002309
2310 if (buf_backup) {
2311 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002312 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002313 free(buf_backup);
2314 buf_backup = NULL;
2315 }
2316 ly_buf_used--;
2317
Michal Vasko22448d32016-03-16 13:17:29 +01002318 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002319 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2320 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2321 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002322 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002323 return NULL;
2324 }
2325 } else {
2326 prefix_mod = prev_mod;
2327 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002328 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002329 continue;
2330 }
2331
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002332 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002333 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002334 llist = (struct lyd_node_leaf_list *)sibling;
2335
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002336 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002337 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002338 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 +02002339 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2340 *parsed = -1;
2341 return NULL;
2342 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002343 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2344 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2345 *parsed = -1;
2346 return NULL;
2347 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002348 } else {
2349 r = 0;
2350 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002351 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002352 }
2353 }
2354
Michal Vasko9ba34de2016-12-07 12:21:19 +01002355 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002356 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002357 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2358 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002359 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2360 } else {
2361 data_val = llist->value_str;
2362 }
2363
2364 if ((!llist_value && data_val && data_val[0])
2365 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002366 continue;
2367 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002368
Michal Vaskof0a50972016-10-19 11:33:55 +02002369 id += r;
2370 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002371 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002372
Radek Krejci45826012016-08-24 15:07:57 +02002373 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002374 /* 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 +01002375 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002376 /* none match */
2377 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002378 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002379
2380 ++list_instance_position;
2381 r = 0;
2382 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002383 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002384 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002385 return NULL;
2386 } else if (ret == 1) {
2387 /* this list instance does not match */
2388 continue;
2389 }
2390 id += r;
2391 last_parsed += r;
2392 }
2393
2394 *parsed += last_parsed;
2395
2396 /* the result node? */
2397 if (!id[0]) {
2398 return sibling;
2399 }
2400
2401 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002402 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002403 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002404 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002405 return NULL;
2406 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002407 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002408 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002409 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002410 break;
2411 }
2412 }
2413
2414 /* no match, return last match */
2415 if (!sibling) {
2416 return last_match;
2417 }
2418
2419 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 +01002420 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002421 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002422 return NULL;
2423 }
2424 id += r;
2425 last_parsed = r;
2426 }
2427
2428 /* cannot get here */
2429 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002430 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002431 return NULL;
2432}
2433
Michal Vasko3edeaf72016-02-11 13:17:43 +01002434/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002435 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002436 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002437 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002438 * @param[in] str_restr Restriction as a string.
2439 * @param[in] type Type of the restriction.
2440 * @param[out] ret Final interval structure that starts with
2441 * the interval of the initial type, continues with intervals
2442 * of any superior types derived from the initial one, and
2443 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002444 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002445 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002446 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002447int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002448resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002449{
2450 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002451 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002452 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002453 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002454 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002455 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002456 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002457
2458 switch (type->base) {
2459 case LY_TYPE_BINARY:
2460 kind = 0;
2461 local_umin = 0;
2462 local_umax = 18446744073709551615UL;
2463
2464 if (!str_restr && type->info.binary.length) {
2465 str_restr = type->info.binary.length->expr;
2466 }
2467 break;
2468 case LY_TYPE_DEC64:
2469 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002470 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2471 local_fmax = __INT64_C(9223372036854775807);
2472 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002473
2474 if (!str_restr && type->info.dec64.range) {
2475 str_restr = type->info.dec64.range->expr;
2476 }
2477 break;
2478 case LY_TYPE_INT8:
2479 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002480 local_smin = __INT64_C(-128);
2481 local_smax = __INT64_C(127);
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_INT16:
2488 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002489 local_smin = __INT64_C(-32768);
2490 local_smax = __INT64_C(32767);
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_INT32:
2497 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002498 local_smin = __INT64_C(-2147483648);
2499 local_smax = __INT64_C(2147483647);
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_INT64:
2506 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002507 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2508 local_smax = __INT64_C(9223372036854775807);
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_UINT8:
2515 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002516 local_umin = __UINT64_C(0);
2517 local_umax = __UINT64_C(255);
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_UINT16:
2524 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002525 local_umin = __UINT64_C(0);
2526 local_umax = __UINT64_C(65535);
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_UINT32:
2533 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002534 local_umin = __UINT64_C(0);
2535 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002536
2537 if (!str_restr && type->info.num.range) {
2538 str_restr = type->info.num.range->expr;
2539 }
2540 break;
2541 case LY_TYPE_UINT64:
2542 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002543 local_umin = __UINT64_C(0);
2544 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002545
2546 if (!str_restr && type->info.num.range) {
2547 str_restr = type->info.num.range->expr;
2548 }
2549 break;
2550 case LY_TYPE_STRING:
2551 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002552 local_umin = __UINT64_C(0);
2553 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002554
2555 if (!str_restr && type->info.str.length) {
2556 str_restr = type->info.str.length->expr;
2557 }
2558 break;
2559 default:
2560 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002561 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002562 }
2563
2564 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002565 if (type->der) {
2566 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002567 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002568 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002569 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570 assert(!intv || (intv->kind == kind));
2571 }
2572
2573 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002574 /* we do not have any restriction, return superior ones */
2575 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002576 return EXIT_SUCCESS;
2577 }
2578
2579 /* adjust local min and max */
2580 if (intv) {
2581 tmp_intv = intv;
2582
2583 if (kind == 0) {
2584 local_umin = tmp_intv->value.uval.min;
2585 } else if (kind == 1) {
2586 local_smin = tmp_intv->value.sval.min;
2587 } else if (kind == 2) {
2588 local_fmin = tmp_intv->value.fval.min;
2589 }
2590
2591 while (tmp_intv->next) {
2592 tmp_intv = tmp_intv->next;
2593 }
2594
2595 if (kind == 0) {
2596 local_umax = tmp_intv->value.uval.max;
2597 } else if (kind == 1) {
2598 local_smax = tmp_intv->value.sval.max;
2599 } else if (kind == 2) {
2600 local_fmax = tmp_intv->value.fval.max;
2601 }
2602 }
2603
2604 /* finally parse our restriction */
2605 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002606 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002607 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002608 if (!tmp_local_intv) {
2609 assert(!local_intv);
2610 local_intv = malloc(sizeof *local_intv);
2611 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002612 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002613 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002614 tmp_local_intv = tmp_local_intv->next;
2615 }
Michal Vasko253035f2015-12-17 16:58:13 +01002616 if (!tmp_local_intv) {
2617 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002618 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002619 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002620
2621 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002622 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002623 tmp_local_intv->next = NULL;
2624
2625 /* min */
2626 ptr = seg_ptr;
2627 while (isspace(ptr[0])) {
2628 ++ptr;
2629 }
2630 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2631 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002632 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002634 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002635 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002636 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2637 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2638 goto error;
2639 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002640 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002641 } else if (!strncmp(ptr, "min", 3)) {
2642 if (kind == 0) {
2643 tmp_local_intv->value.uval.min = local_umin;
2644 } else if (kind == 1) {
2645 tmp_local_intv->value.sval.min = local_smin;
2646 } else if (kind == 2) {
2647 tmp_local_intv->value.fval.min = local_fmin;
2648 }
2649
2650 ptr += 3;
2651 } else if (!strncmp(ptr, "max", 3)) {
2652 if (kind == 0) {
2653 tmp_local_intv->value.uval.min = local_umax;
2654 } else if (kind == 1) {
2655 tmp_local_intv->value.sval.min = local_smax;
2656 } else if (kind == 2) {
2657 tmp_local_intv->value.fval.min = local_fmax;
2658 }
2659
2660 ptr += 3;
2661 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002662 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002663 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664 }
2665
2666 while (isspace(ptr[0])) {
2667 ptr++;
2668 }
2669
2670 /* no interval or interval */
2671 if ((ptr[0] == '|') || !ptr[0]) {
2672 if (kind == 0) {
2673 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2674 } else if (kind == 1) {
2675 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2676 } else if (kind == 2) {
2677 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2678 }
2679 } else if (!strncmp(ptr, "..", 2)) {
2680 /* skip ".." */
2681 ptr += 2;
2682 while (isspace(ptr[0])) {
2683 ++ptr;
2684 }
2685
2686 /* max */
2687 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2688 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002689 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002690 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002691 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002692 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002693 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2694 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2695 goto error;
2696 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002697 }
2698 } else if (!strncmp(ptr, "max", 3)) {
2699 if (kind == 0) {
2700 tmp_local_intv->value.uval.max = local_umax;
2701 } else if (kind == 1) {
2702 tmp_local_intv->value.sval.max = local_smax;
2703 } else if (kind == 2) {
2704 tmp_local_intv->value.fval.max = local_fmax;
2705 }
2706 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002707 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002708 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002709 }
2710 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002711 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002712 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002713 }
2714
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002715 /* check min and max in correct order*/
2716 if (kind == 0) {
2717 /* current segment */
2718 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2719 goto error;
2720 }
2721 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2722 goto error;
2723 }
2724 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002725 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002726 goto error;
2727 }
2728 } else if (kind == 1) {
2729 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2730 goto error;
2731 }
2732 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2733 goto error;
2734 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002735 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002736 goto error;
2737 }
2738 } else if (kind == 2) {
2739 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2740 goto error;
2741 }
2742 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2743 goto error;
2744 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002745 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002746 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002747 goto error;
2748 }
2749 }
2750
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002751 /* next segment (next OR) */
2752 seg_ptr = strchr(seg_ptr, '|');
2753 if (!seg_ptr) {
2754 break;
2755 }
2756 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002757 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002758 }
2759
2760 /* check local restrictions against superior ones */
2761 if (intv) {
2762 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002763 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002764
2765 while (tmp_local_intv && tmp_intv) {
2766 /* reuse local variables */
2767 if (kind == 0) {
2768 local_umin = tmp_local_intv->value.uval.min;
2769 local_umax = tmp_local_intv->value.uval.max;
2770
2771 /* it must be in this interval */
2772 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2773 /* this interval is covered, next one */
2774 if (local_umax <= tmp_intv->value.uval.max) {
2775 tmp_local_intv = tmp_local_intv->next;
2776 continue;
2777 /* ascending order of restrictions -> fail */
2778 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002779 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002780 }
2781 }
2782 } else if (kind == 1) {
2783 local_smin = tmp_local_intv->value.sval.min;
2784 local_smax = tmp_local_intv->value.sval.max;
2785
2786 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2787 if (local_smax <= tmp_intv->value.sval.max) {
2788 tmp_local_intv = tmp_local_intv->next;
2789 continue;
2790 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002791 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002792 }
2793 }
2794 } else if (kind == 2) {
2795 local_fmin = tmp_local_intv->value.fval.min;
2796 local_fmax = tmp_local_intv->value.fval.max;
2797
Michal Vasko4d1f0482016-09-19 14:35:06 +02002798 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002799 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002800 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002801 tmp_local_intv = tmp_local_intv->next;
2802 continue;
2803 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002804 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002805 }
2806 }
2807 }
2808
2809 tmp_intv = tmp_intv->next;
2810 }
2811
2812 /* some interval left uncovered -> fail */
2813 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002814 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002815 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002816 }
2817
Michal Vaskoaeb51802016-04-11 10:58:47 +02002818 /* append the local intervals to all the intervals of the superior types, return it all */
2819 if (intv) {
2820 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2821 tmp_intv->next = local_intv;
2822 } else {
2823 intv = local_intv;
2824 }
2825 *ret = intv;
2826
2827 return EXIT_SUCCESS;
2828
2829error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002830 while (intv) {
2831 tmp_intv = intv->next;
2832 free(intv);
2833 intv = tmp_intv;
2834 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002835 while (local_intv) {
2836 tmp_local_intv = local_intv->next;
2837 free(local_intv);
2838 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002839 }
2840
Michal Vaskoaeb51802016-04-11 10:58:47 +02002841 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002842}
2843
Michal Vasko730dfdf2015-08-11 14:48:05 +02002844/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002845 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2846 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002847 *
2848 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002849 * @param[in] mod_name Typedef name module name.
2850 * @param[in] module Main module.
2851 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002852 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002853 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002854 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002855 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002856int
Michal Vasko1e62a092015-12-01 12:27:20 +01002857resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2858 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002859{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002860 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002861 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002862 int tpdf_size;
2863
Michal Vasko1dca6882015-10-22 14:29:42 +02002864 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 /* no prefix, try built-in types */
2866 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002867 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002868 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002869 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002870 }
2871 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002872 }
2873 }
2874 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002875 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002876 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002877 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002878 }
2879 }
2880
Michal Vasko1dca6882015-10-22 14:29:42 +02002881 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002882 /* search in local typedefs */
2883 while (parent) {
2884 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002885 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002886 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2887 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002888 break;
2889
Radek Krejci76512572015-08-04 09:47:08 +02002890 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002891 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2892 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002893 break;
2894
Radek Krejci76512572015-08-04 09:47:08 +02002895 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002896 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2897 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 break;
2899
Radek Krejci76512572015-08-04 09:47:08 +02002900 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002901 case LYS_ACTION:
2902 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2903 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002904 break;
2905
Radek Krejci76512572015-08-04 09:47:08 +02002906 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002907 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2908 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002909 break;
2910
Radek Krejci76512572015-08-04 09:47:08 +02002911 case LYS_INPUT:
2912 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002913 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2914 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002915 break;
2916
2917 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002918 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002919 continue;
2920 }
2921
2922 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002923 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002924 match = &tpdf[i];
2925 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926 }
2927 }
2928
Michal Vaskodcf98e62016-05-05 17:53:53 +02002929 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930 }
Radek Krejcic071c542016-01-27 14:57:51 +01002931 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002933 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002934 if (!module) {
2935 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002936 }
2937 }
2938
2939 /* search in top level typedefs */
2940 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002941 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002942 match = &module->tpdf[i];
2943 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002944 }
2945 }
2946
2947 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002948 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002950 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 +02002951 match = &module->inc[i].submodule->tpdf[j];
2952 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002953 }
2954 }
2955 }
2956
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002957 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002958
2959check_leafref:
2960 if (ret) {
2961 *ret = match;
2962 }
2963 if (match->type.base == LY_TYPE_LEAFREF) {
2964 while (!match->type.info.lref.path) {
2965 match = match->type.der;
2966 assert(match);
2967 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002968 }
2969 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970}
2971
Michal Vasko1dca6882015-10-22 14:29:42 +02002972/**
2973 * @brief Check the default \p value of the \p type. Logs directly.
2974 *
2975 * @param[in] type Type definition to use.
2976 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002977 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002978 *
2979 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2980 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002981static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01002982check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002983{
Radek Krejcibad2f172016-08-02 11:04:15 +02002984 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002985 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002986 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01002987 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002988
Radek Krejci51673202016-11-01 17:00:32 +01002989 assert(value);
2990
Radek Krejcic13db382016-08-16 10:52:42 +02002991 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002992 /* the type was not resolved yet, nothing to do for now */
2993 return EXIT_FAILURE;
Radek Krejciab08f0f2017-03-09 16:37:15 +01002994 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
2995 /* leafref in typedef cannot be checked */
2996 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002997 }
2998
Radek Krejci51673202016-11-01 17:00:32 +01002999 dflt = *value;
3000 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003001 /* we do not have a new default value, so is there any to check even, in some base type? */
3002 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3003 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003004 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003005 break;
3006 }
3007 }
3008
Radek Krejci51673202016-11-01 17:00:32 +01003009 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003010 /* no default value, nothing to check, all is well */
3011 return EXIT_SUCCESS;
3012 }
3013
3014 /* 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)? */
3015 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003016 case LY_TYPE_IDENT:
3017 case LY_TYPE_INST:
3018 case LY_TYPE_LEAFREF:
3019 case LY_TYPE_BOOL:
3020 case LY_TYPE_EMPTY:
3021 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3022 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003023 case LY_TYPE_BITS:
3024 /* the default value must match the restricted list of values, if the type was restricted */
3025 if (type->info.bits.count) {
3026 break;
3027 }
3028 return EXIT_SUCCESS;
3029 case LY_TYPE_ENUM:
3030 /* the default value must match the restricted list of values, if the type was restricted */
3031 if (type->info.enums.count) {
3032 break;
3033 }
3034 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003035 case LY_TYPE_DEC64:
3036 if (type->info.dec64.range) {
3037 break;
3038 }
3039 return EXIT_SUCCESS;
3040 case LY_TYPE_BINARY:
3041 if (type->info.binary.length) {
3042 break;
3043 }
3044 return EXIT_SUCCESS;
3045 case LY_TYPE_INT8:
3046 case LY_TYPE_INT16:
3047 case LY_TYPE_INT32:
3048 case LY_TYPE_INT64:
3049 case LY_TYPE_UINT8:
3050 case LY_TYPE_UINT16:
3051 case LY_TYPE_UINT32:
3052 case LY_TYPE_UINT64:
3053 if (type->info.num.range) {
3054 break;
3055 }
3056 return EXIT_SUCCESS;
3057 case LY_TYPE_STRING:
3058 if (type->info.str.length || type->info.str.patterns) {
3059 break;
3060 }
3061 return EXIT_SUCCESS;
3062 case LY_TYPE_UNION:
3063 /* way too much trouble learning whether we need to check the default again, so just do it */
3064 break;
3065 default:
3066 LOGINT;
3067 return -1;
3068 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003069 } else if (type->base == LY_TYPE_EMPTY) {
3070 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3071 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3072 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003073 }
3074
Michal Vasko1dca6882015-10-22 14:29:42 +02003075 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003076 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003077 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003078 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003079 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003080 if (!node.schema) {
3081 LOGMEM;
3082 return -1;
3083 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003084 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003085 if (!node.schema->name) {
3086 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003087 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003088 return -1;
3089 }
Michal Vasko56826402016-03-02 11:11:37 +01003090 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003091 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003092
Radek Krejci37b756f2016-01-18 10:15:03 +01003093 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003094 if (!type->info.lref.target) {
3095 ret = EXIT_FAILURE;
3096 goto finish;
3097 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003098 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003099 if (!ret) {
3100 /* adopt possibly changed default value to its canonical form */
3101 if (*value) {
3102 *value = dflt;
3103 }
3104 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003105 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003106 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 +01003107 /* possible forward reference */
3108 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003109 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003110 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003111 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3112 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3113 /* we have refined bits/enums */
3114 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3115 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003116 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003117 }
3118 }
Radek Krejci51673202016-11-01 17:00:32 +01003119 } else {
3120 /* success - adopt canonical form from the node into the default value */
3121 if (dflt != node.value_str) {
3122 /* this can happen only if we have non-inherited default value,
3123 * inherited default values are already in canonical form */
3124 assert(dflt == *value);
3125 *value = node.value_str;
3126 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003127 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003128 }
3129
3130finish:
3131 if (node.value_type == LY_TYPE_BITS) {
3132 free(node.value.bit);
3133 }
3134 free((char *)node.schema->name);
3135 free(node.schema);
3136
3137 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138}
3139
Michal Vasko730dfdf2015-08-11 14:48:05 +02003140/**
3141 * @brief Check a key for mandatory attributes. Logs directly.
3142 *
3143 * @param[in] key The key to check.
3144 * @param[in] flags What flags to check.
3145 * @param[in] list The list of all the keys.
3146 * @param[in] index Index of the key in the key list.
3147 * @param[in] name The name of the keys.
3148 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003149 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003150 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003151 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003152static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003153check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003154{
Radek Krejciadb57612016-02-16 13:34:34 +01003155 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 char *dup = NULL;
3157 int j;
3158
3159 /* existence */
3160 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003161 if (name[len] != '\0') {
3162 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003163 if (!dup) {
3164 LOGMEM;
3165 return -1;
3166 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003167 dup[len] = '\0';
3168 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003169 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003170 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003171 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003172 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003173 }
3174
3175 /* uniqueness */
3176 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003177 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003178 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003179 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180 }
3181 }
3182
3183 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003184 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003185 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003186 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187 }
3188
3189 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003190 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003191 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003192 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003193 }
3194
3195 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003196 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003197 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003198 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003199 }
3200
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003201 /* key is not placed from augment */
3202 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003203 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003204 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003205 return -1;
3206 }
3207
Radek Krejci3f21ada2016-08-01 13:34:31 +02003208 /* key is not when/if-feature -conditional */
3209 j = 0;
3210 if (key->when || (key->iffeature_size && (j = 1))) {
3211 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003212 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003213 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003214 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003215 }
3216
Michal Vasko0b85aa82016-03-07 14:37:43 +01003217 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003218}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003219
3220/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003221 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003222 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003223 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003224 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003225 *
3226 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3227 */
3228int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003229resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003230{
Radek Krejci581ce772015-11-10 17:22:40 +01003231 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003232 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003233
Michal Vaskodc300b02017-04-07 14:09:20 +02003234 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003235 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003236 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003237 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003238 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003239 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003240 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003241 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003242 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003243 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003244 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003245 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003246 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003247 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 }
Radek Krejci581ce772015-11-10 17:22:40 +01003249 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003250 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003251 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003252 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003253 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003254 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255 }
3256
Radek Krejcicf509982015-12-15 09:22:44 +01003257 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003258 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3259 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003260 return -1;
3261 }
3262
Radek Krejcid09d1a52016-08-11 14:05:45 +02003263 /* check that all unique's targets are of the same config type */
3264 if (*trg_type) {
3265 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3266 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003267 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003268 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3269 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3270 return -1;
3271 }
3272 } else {
3273 /* first unique */
3274 if (leaf->flags & LYS_CONFIG_W) {
3275 *trg_type = 1;
3276 } else {
3277 *trg_type = 2;
3278 }
3279 }
3280
Radek Krejcica7efb72016-01-18 13:06:01 +01003281 /* set leaf's unique flag */
3282 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3283
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003284 return EXIT_SUCCESS;
3285
3286error:
3287
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003288 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289}
3290
Radek Krejci0c0086a2016-03-24 15:20:28 +01003291void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003292unres_data_del(struct unres_data *unres, uint32_t i)
3293{
3294 /* there are items after the one deleted */
3295 if (i+1 < unres->count) {
3296 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003297 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003298
3299 /* deleting the last item */
3300 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003301 free(unres->node);
3302 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003303 }
3304
3305 /* if there are no items after and it is not the last one, just move the counter */
3306 --unres->count;
3307}
3308
Michal Vasko0491ab32015-08-19 14:28:29 +02003309/**
3310 * @brief Resolve (find) a data node from a specific module. Does not log.
3311 *
3312 * @param[in] mod Module to search in.
3313 * @param[in] name Name of the data node.
3314 * @param[in] nam_len Length of the name.
3315 * @param[in] start Data node to start the search from.
3316 * @param[in,out] parents Resolved nodes. If there are some parents,
3317 * they are replaced (!!) with the resolvents.
3318 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003319 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003320 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003321static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003322resolve_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 +02003323{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003324 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003325 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003326 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003327
Michal Vasko23b61ec2015-08-19 11:19:50 +02003328 if (!parents->count) {
3329 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003330 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003331 if (!parents->node) {
3332 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003333 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003334 }
Michal Vaskocf024702015-10-08 15:01:42 +02003335 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003336 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003337 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003338 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003340 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003341 continue;
3342 }
3343 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003344 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3346 && node->schema->name[nam_len] == '\0') {
3347 /* matching target */
3348 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003349 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003350 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351 flag = 1;
3352 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003353 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003354 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003355 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3356 if (!parents->node) {
3357 return EXIT_FAILURE;
3358 }
Michal Vaskocf024702015-10-08 15:01:42 +02003359 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003360 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003361 }
3362 }
3363 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003364
3365 if (!flag) {
3366 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003367 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003368 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003370 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371 }
3372
Michal Vasko0491ab32015-08-19 14:28:29 +02003373 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003374}
3375
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003376/**
3377 * @brief Resolve (find) a data node. Does not log.
3378 *
Radek Krejci581ce772015-11-10 17:22:40 +01003379 * @param[in] mod_name Module name of the data node.
3380 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003381 * @param[in] name Name of the data node.
3382 * @param[in] nam_len Length of the name.
3383 * @param[in] start Data node to start the search from.
3384 * @param[in,out] parents Resolved nodes. If there are some parents,
3385 * they are replaced (!!) with the resolvents.
3386 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003387 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003388 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003389static int
Radek Krejci581ce772015-11-10 17:22:40 +01003390resolve_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 +02003391 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003392{
Michal Vasko1e62a092015-12-01 12:27:20 +01003393 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003394 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003395
Michal Vasko23b61ec2015-08-19 11:19:50 +02003396 assert(start);
3397
Michal Vasko31fc3672015-10-21 12:08:13 +02003398 if (mod_name) {
3399 /* we have mod_name, find appropriate module */
3400 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003401 if (!str) {
3402 LOGMEM;
3403 return -1;
3404 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003405 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3406 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003407 if (!mod) {
3408 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003409 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003410 }
3411 } else {
3412 /* no prefix, module is the same as of current node */
3413 mod = start->schema->module;
3414 }
3415
3416 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417}
3418
Michal Vasko730dfdf2015-08-11 14:48:05 +02003419/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003420 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003421 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003422 *
Michal Vaskobb211122015-08-19 14:03:11 +02003423 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003424 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003425 * @param[in,out] node_match Nodes satisfying the restriction
3426 * without the predicate. Nodes not
3427 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003428 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003429 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003430 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003431 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003433resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003434 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003436 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003437 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003438 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003439 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3440 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003441 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003442 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003443
3444 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003445 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003446 if (!source_match.node) {
3447 LOGMEM;
3448 return -1;
3449 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003450 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003451 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003452 if (!dest_match.node) {
3453 LOGMEM;
3454 return -1;
3455 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456
3457 do {
3458 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3459 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003460 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003461 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003462 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003463 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003464 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465 pred += i;
3466
Michal Vasko23b61ec2015-08-19 11:19:50 +02003467 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003469 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003470
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003471 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003472 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003473 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003474 i = 0;
3475 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476 }
3477
3478 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003479 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3482 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003483 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003484 rc = -1;
3485 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003487 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003488 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003489 dest_match.node[0] = dest_match.node[0]->parent;
3490 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003491 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003492 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003493 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003494 }
3495 }
3496 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003497 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003498 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003499 i = 0;
3500 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 }
3502
3503 if (pke_len == pke_parsed) {
3504 break;
3505 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003506 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 +02003507 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003508 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003509 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003510 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511 }
3512 pke_parsed += i;
3513 }
3514
3515 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003516 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003517 while (leaf_dst && leaf_dst->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003518 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3519 }
3520 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003521 while (leaf_src && leaf_src->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003522 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3523 }
Radek Krejci981a8ee2017-03-17 16:48:26 +01003524 if (!leaf_src || !leaf_dst) {
3525 /* not yet resolved leafrefs */
3526 return EXIT_FAILURE;
3527 }
Radek Krejcic7408e72017-03-17 10:43:51 +01003528 if ((leaf_src->value_type & LY_DATA_TYPE_MASK) != (leaf_dst->value_type & LY_DATA_TYPE_MASK)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003529 goto remove_leafref;
3530 }
3531
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003532 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003533 goto remove_leafref;
3534 }
3535
3536 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003537 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003538 continue;
3539
3540remove_leafref:
3541 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003542 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003543 }
3544 } while (has_predicate);
3545
Michal Vaskocf024702015-10-08 15:01:42 +02003546 free(source_match.node);
3547 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003548 if (parsed) {
3549 *parsed = parsed_loc;
3550 }
3551 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003552
3553error:
3554
3555 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003556 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003557 }
3558 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003559 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003560 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003561 if (parsed) {
3562 *parsed = -parsed_loc+i;
3563 }
3564 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565}
3566
Michal Vasko730dfdf2015-08-11 14:48:05 +02003567/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003568 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003569 *
Michal Vaskocf024702015-10-08 15:01:42 +02003570 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003572 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003573 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003574 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003575 */
Michal Vasko184521f2015-09-24 13:14:26 +02003576static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003577resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578{
Radek Krejci71b795b2015-08-10 16:20:39 +02003579 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003580 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003581 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003582 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003583
Michal Vaskocf024702015-10-08 15:01:42 +02003584 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003585
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003587 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588
3589 /* searching for nodeset */
3590 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003591 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 +01003592 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003593 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003594 goto error;
3595 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003596 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003597 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003598
Michal Vasko23b61ec2015-08-19 11:19:50 +02003599 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003600 if (parent_times > 0) {
3601 data = node;
3602 for (i = 1; i < parent_times; ++i) {
3603 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003604 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003605 } else if (!parent_times) {
3606 data = node->child;
3607 } else {
3608 /* absolute path */
3609 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003610 }
3611
Michal Vaskobfd98e62016-09-02 09:50:05 +02003612 /* we may still be parsing it and the pointer is not correct yet */
3613 if (data->prev) {
3614 while (data->prev->next) {
3615 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003616 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617 }
3618 }
3619
3620 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003621 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003622 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003623 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003624 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625 goto error;
3626 }
3627
3628 if (has_predicate) {
3629 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003630 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003631 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3632 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003633 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003634 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003635 continue;
3636 }
3637
3638 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003639 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003640 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003641 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003642 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003643 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003644 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645 goto error;
3646 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003648 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003649
Michal Vasko23b61ec2015-08-19 11:19:50 +02003650 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003651 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003652 goto error;
3653 }
3654 }
3655 } while (path[0] != '\0');
3656
Michal Vaskof02e3742015-08-05 16:27:02 +02003657 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658
3659error:
3660
Michal Vaskocf024702015-10-08 15:01:42 +02003661 free(ret->node);
3662 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003663 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003664
Michal Vasko0491ab32015-08-19 14:28:29 +02003665 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003666}
3667
Michal Vaskoe27516a2016-10-10 17:55:31 +00003668static int
Michal Vasko1c007172017-03-10 10:20:44 +01003669resolve_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 +00003670{
3671 int dep1, dep2;
3672 const struct lys_node *node;
3673
3674 if (lys_parent(op_node)) {
3675 /* inner operation (notif/action) */
3676 if (abs_path) {
3677 return 1;
3678 } else {
3679 /* compare depth of both nodes */
3680 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3681 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3682 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3683 return 1;
3684 }
3685 }
3686 } else {
3687 /* top-level operation (notif/rpc) */
3688 if (op_node != first_node) {
3689 return 1;
3690 }
3691 }
3692
3693 return 0;
3694}
3695
Michal Vasko730dfdf2015-08-11 14:48:05 +02003696/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003697 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003698 *
Michal Vaskobb211122015-08-19 14:03:11 +02003699 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003700 * @param[in] context_node Predicate context node (where the predicate is placed).
3701 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003702 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003703 *
Michal Vasko184521f2015-09-24 13:14:26 +02003704 * @return 0 on forward reference, otherwise the number
3705 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003706 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003707 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003708static int
Michal Vasko1c007172017-03-10 10:20:44 +01003709resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3710 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003711{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003712 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003713 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003714 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003715 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3716 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003717
3718 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003719 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003720 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003721 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 return -parsed+i;
3723 }
3724 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003725 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003726
Michal Vasko58090902015-08-13 14:04:15 +02003727 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003728 if (sour_pref) {
3729 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3730 } else {
3731 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003732 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003733 rc = lys_get_data_sibling(trg_mod, context_node->child, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003734 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003735 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003736 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003737 }
3738
3739 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003740 dest_parent_times = 0;
3741 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003742 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3743 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003744 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 +02003745 return -parsed;
3746 }
3747 pke_parsed += i;
3748
Radek Krejciadb57612016-02-16 13:34:34 +01003749 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003750 /* path is supposed to be evaluated in data tree, so we have to skip
3751 * all schema nodes that cannot be instantiated in data tree */
3752 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003753 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003754 dst_node = lys_parent(dst_node));
3755
Michal Vasko1f76a282015-08-04 16:16:53 +02003756 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003757 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003758 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 }
3760 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003761 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003762 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003763 if (dest_pref) {
3764 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3765 } else {
3766 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003767 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003768 rc = lys_get_data_sibling(trg_mod, dst_node->child, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003769 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003770 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003771 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 }
3773
Michal Vaskoe27516a2016-10-10 17:55:31 +00003774 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003775 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003776 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003777 }
3778 first_iter = 0;
3779 }
3780
Michal Vasko1f76a282015-08-04 16:16:53 +02003781 if (pke_len == pke_parsed) {
3782 break;
3783 }
3784
3785 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3786 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003787 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003788 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 return -parsed;
3790 }
3791 pke_parsed += i;
3792 }
3793
3794 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003795 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003796 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003797 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003798 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003799 return -parsed;
3800 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003801 } while (has_predicate);
3802
3803 return parsed;
3804}
3805
Michal Vasko730dfdf2015-08-11 14:48:05 +02003806/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003807 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003808 *
Michal Vaskobb211122015-08-19 14:03:11 +02003809 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003810 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003811 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003812 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003814 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003815static int
Michal Vasko1c007172017-03-10 10:20:44 +01003816resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003817{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003818 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003819 const struct lys_module *mod;
3820 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003821 const char *id, *prefix, *name;
3822 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003823 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003824
Michal Vasko184521f2015-09-24 13:14:26 +02003825 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 parent_times = 0;
3827 id = path;
3828
Michal Vasko1c007172017-03-10 10:20:44 +01003829 /* find operation schema we are in */
3830 for (op_node = lys_parent(parent);
3831 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3832 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003833
Radek Krejci990af1f2016-11-09 13:53:36 +01003834 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003835 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003836 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 +01003837 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003838 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003839 }
3840 id += i;
3841
Michal Vasko184521f2015-09-24 13:14:26 +02003842 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003843 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003844 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003845 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3846 if (!mod) {
Michal Vasko1c007172017-03-10 10:20:44 +01003847 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003848 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003849 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003850 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003851 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003852 if (!mod->implemented) {
3853 /* make the found module implemented */
3854 if (lys_set_implemented(mod)) {
3855 return EXIT_FAILURE;
3856 }
3857 }
3858 }
3859 /* get start node */
3860 if (!mod->data) {
Michal Vasko1c007172017-03-10 10:20:44 +01003861 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Radek Krejci990af1f2016-11-09 13:53:36 +01003862 return EXIT_FAILURE;
3863 }
3864 node = mod->data;
3865
Michal Vasko1f76a282015-08-04 16:16:53 +02003866 } else if (parent_times > 0) {
Michal Vasko94458082016-10-07 14:34:36 +02003867 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3868 for (i = 0, node = parent; i < parent_times - 1; 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 Vaskoe9914d12016-10-07 14:32:37 +02003876 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003877 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003878 }
3879 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003880
3881 /* now we have to check that if we are going into a node from a different module,
3882 * the module is implemented (so its augments are applied) */
3883 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3884 if (!mod) {
3885 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3886 return EXIT_FAILURE;
3887 }
3888 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003889 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003890 if (!mod->implemented) {
3891 /* make the found module implemented */
3892 if (lys_set_implemented(mod)) {
3893 return EXIT_FAILURE;
3894 }
3895 }
3896 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003897 } else {
3898 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003899 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003900 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003901 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003902 /* we have to first check that the module we are going into is implemented */
3903 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3904 if (!mod) {
3905 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3906 return EXIT_FAILURE;
3907 }
3908 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003909 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003910 if (!mod->implemented) {
3911 /* make the found module implemented */
3912 if (lys_set_implemented(mod)) {
3913 return EXIT_FAILURE;
3914 }
3915 }
3916 }
3917
Michal Vasko7dc71d02016-03-15 10:42:28 +01003918 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003919 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003920 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003921 return -1;
3922 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003923 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003924 if (!node) {
Michal Vasko1c007172017-03-10 10:20:44 +01003925 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003926 return EXIT_FAILURE;
3927 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003928 }
3929
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003930 rc = lys_get_data_sibling(mod, node, name, nam_len, LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF
3931 | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003932 if (rc) {
Michal Vasko1c007172017-03-10 10:20:44 +01003933 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003934 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003935 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003936
Michal Vaskoe27516a2016-10-10 17:55:31 +00003937 if (first_iter) {
3938 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003939 if (op_node && parent_times &&
3940 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003941 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003942 }
3943 first_iter = 0;
3944 }
3945
Michal Vasko1f76a282015-08-04 16:16:53 +02003946 if (has_predicate) {
3947 /* we have predicate, so the current result must be list */
3948 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003949 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003950 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003951 }
3952
Michal Vasko1c007172017-03-10 10:20:44 +01003953 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003954 if (i <= 0) {
3955 if (i == 0) {
3956 return EXIT_FAILURE;
3957 } else { /* i < 0 */
3958 return -1;
3959 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003960 }
3961 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003962 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003963 }
3964 } while (id[0]);
3965
Michal Vaskoca917682016-07-25 11:00:37 +02003966 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003967 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003968 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003969 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 +02003970 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003971 }
3972
Radek Krejcicf509982015-12-15 09:22:44 +01003973 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003974 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003975 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003976 return -1;
3977 }
3978
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003979 if (ret) {
3980 *ret = node;
3981 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003982
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003983 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003984}
3985
Michal Vasko730dfdf2015-08-11 14:48:05 +02003986/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003987 * @brief Resolve instance-identifier predicate in JSON data format.
3988 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003989 *
Michal Vaskobb211122015-08-19 14:03:11 +02003990 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003991 * @param[in,out] node_match Nodes matching the restriction without
3992 * the predicate. Nodes not satisfying
3993 * the predicate are removed.
3994 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003995 * @return Number of characters successfully parsed,
3996 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003997 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003998static int
Michal Vasko1c007172017-03-10 10:20:44 +01003999resolve_instid_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004000{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004001 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004002 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004003 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004004 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004005 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004006
Michal Vasko1f2cc332015-08-19 11:18:32 +02004007 assert(pred && node_match->count);
4008
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004009 idx = -1;
4010 parsed = 0;
4011
Michal Vaskob2f40be2016-09-08 16:03:48 +02004012 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004013 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004014 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004015 return -parsed+i;
4016 }
4017 parsed += i;
4018 pred += i;
4019
4020 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004021 /* pos */
4022 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004023 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004024 } else if (name[0] != '.') {
4025 /* list keys */
4026 if (pred_iter < 0) {
4027 pred_iter = 1;
4028 } else {
4029 ++pred_iter;
4030 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004031 }
4032
Michal Vaskof2f28a12016-09-09 12:43:06 +02004033 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004034 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004036 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004037 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004038 goto remove_instid;
4039 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004040
4041 target = node_match->node[j];
4042 /* check the value */
4043 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4044 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4045 goto remove_instid;
4046 }
4047
4048 } else if (!value) {
4049 /* keyless list position */
4050 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4051 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4052 goto remove_instid;
4053 }
4054
4055 if (idx != cur_idx) {
4056 goto remove_instid;
4057 }
4058
4059 } else {
4060 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004061 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004062 goto remove_instid;
4063 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004064
4065 /* key module must match the list module */
4066 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4067 || node_match->node[j]->schema->module->name[mod_len]) {
4068 goto remove_instid;
4069 }
4070 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004071 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004072 if (!target) {
4073 goto remove_instid;
4074 }
4075 if ((struct lys_node_leaf *)target->schema !=
4076 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4077 goto remove_instid;
4078 }
4079
4080 /* check the value */
4081 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4082 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4083 goto remove_instid;
4084 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085 }
4086
Michal Vaskob2f40be2016-09-08 16:03:48 +02004087 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004088 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004089 continue;
4090
4091remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004092 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004093 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004094 }
4095 } while (has_predicate);
4096
Michal Vaskob2f40be2016-09-08 16:03:48 +02004097 /* check that all list keys were specified */
4098 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004099 j = 0;
4100 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004101 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4102 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4103 /* not enough predicates, just remove the list instance */
4104 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004105 } else {
4106 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004107 }
4108 }
4109
4110 if (!node_match->count) {
4111 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4112 }
4113 }
4114
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004115 return parsed;
4116}
4117
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004118int
Michal Vasko769f8032017-01-24 13:11:55 +01004119lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004120{
4121 struct lys_node *parent, *elem;
4122 struct lyxp_set set;
4123 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004124 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004125
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004126 if (check_place) {
4127 parent = node;
4128 while (parent) {
4129 if (parent->nodetype == LYS_GROUPING) {
4130 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004131 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004132 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004133 if (parent->nodetype == LYS_AUGMENT) {
4134 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004135 /* unresolved augment */
4136 if (parent->module->implemented) {
4137 /* skip for now (will be checked later) */
4138 return EXIT_FAILURE;
4139 } else {
4140 /* not implemented augment, skip resolving */
4141 return EXIT_SUCCESS;
4142 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004143 } else {
4144 parent = ((struct lys_node_augment *)parent)->target;
4145 continue;
4146 }
4147 }
4148 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004149 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004150 }
4151
Michal Vasko769f8032017-01-24 13:11:55 +01004152 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4153 if (ret == -1) {
4154 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004155 }
4156
4157 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4158
4159 for (i = 0; i < set.used; ++i) {
4160 /* skip roots'n'stuff */
4161 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4162 /* XPath expression cannot reference "lower" status than the node that has the definition */
4163 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4164 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4165 return -1;
4166 }
4167
4168 if (parent) {
4169 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4170 if (!elem) {
4171 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004172 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004173 break;
4174 }
4175 }
4176 }
4177 }
4178
4179 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004180 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004181}
4182
Radek Krejcif71f48f2016-10-25 16:37:24 +02004183static int
4184check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4185{
4186 int i;
4187
4188 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004189 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4190 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004191 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 +02004192 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4193 return -1;
4194 }
4195 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4196 * of leafref resolving (lys_leaf_add_leafref_target()) */
4197 } else if (type->base == LY_TYPE_UNION) {
4198 for (i = 0; i < type->info.uni.count; i++) {
4199 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4200 return -1;
4201 }
4202 }
4203 }
4204 return 0;
4205}
4206
Michal Vasko9e635ac2016-10-17 11:44:09 +02004207/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004208 * @brief Passes config flag down to children, skips nodes without config flags.
4209 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004210 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004211 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004212 * @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 +02004213 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004214 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004215 *
4216 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004217 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004218static int
Radek Krejcib3142312016-11-09 11:04:12 +01004219inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004220{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004221 struct lys_node_leaf *leaf;
4222
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004223 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004224 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004225 if (clear) {
4226 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004227 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004228 } else {
4229 if (node->flags & LYS_CONFIG_SET) {
4230 /* skip nodes with an explicit config value */
4231 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4232 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004233 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004234 return -1;
4235 }
4236 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004237 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004238
4239 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4240 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4241 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004242 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4243 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004244 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4245 return -1;
4246 }
4247 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004248 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004249 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004250 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004251 return -1;
4252 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004253 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4254 leaf = (struct lys_node_leaf *)node;
4255 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004256 return -1;
4257 }
4258 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004259 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004260
4261 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004262}
4263
Michal Vasko730dfdf2015-08-11 14:48:05 +02004264/**
Michal Vasko7178e692016-02-12 15:58:05 +01004265 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004266 *
Michal Vaskobb211122015-08-19 14:03:11 +02004267 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004268 * @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 +01004269 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004270 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004271 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004272 */
Michal Vasko7178e692016-02-12 15:58:05 +01004273static int
Radek Krejcib3142312016-11-09 11:04:12 +01004274resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004275{
Michal Vaskoe022a562016-09-27 14:24:15 +02004276 int rc, clear_config;
Radek Krejci80056d52017-01-05 13:13:33 +01004277 unsigned int u;
Michal Vasko1d87a922015-08-21 12:57:16 +02004278 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004279 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004280 struct lys_module *mod;
Radek Krejci80056d52017-01-05 13:13:33 +01004281 struct lys_ext_instance *ext;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004282
Michal Vasko15b36692016-08-26 15:29:54 +02004283 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004284 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004285
Michal Vasko15b36692016-08-26 15:29:54 +02004286 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004287 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004288 if (rc == -1) {
4289 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004290 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004291 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4292 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004293 } else if (rc == 0 && aug->target) {
4294 /* augment was resolved as a side effect of setting module implemented when
4295 * resolving augment schema nodeid, so we are done here */
4296 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004297 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004298 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004299 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4300 return EXIT_FAILURE;
4301 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004302 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004303 if (!mod->implemented) {
4304 /* it must be augment only to the same module,
4305 * otherwise we do not apply augment in not-implemented
4306 * module. If the module is set to be implemented in future,
4307 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004308 if (!aug_target) {
4309 /* target was not even resolved */
4310 return EXIT_SUCCESS;
4311 }
4312 /* target was resolved, but it may refer another module */
4313 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004314 if (lys_node_module(sub) != mod) {
4315 /* this is not an implemented module and the augment
4316 * target some other module, so avoid its connecting
4317 * to the target */
4318 return EXIT_SUCCESS;
4319 }
4320 }
4321 }
4322
Michal Vasko15b36692016-08-26 15:29:54 +02004323 if (!aug->child) {
Radek Krejci9bcb9f42017-04-06 12:57:01 +02004324 /* empty augment, warn about it ... */
Michal Vasko15b36692016-08-26 15:29:54 +02004325 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci9bcb9f42017-04-06 12:57:01 +02004326 /* ... but use it, since it has no child, no reconnection work is needed */
4327 aug->target = (struct lys_node *)aug_target;
4328
Radek Krejci27fe55e2016-09-13 17:13:35 +02004329 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004330 }
4331
Michal Vaskod58d5962016-03-02 14:29:41 +01004332 /* check for mandatory nodes - if the target node is in another module
4333 * the added nodes cannot be mandatory
4334 */
Michal Vasko15b36692016-08-26 15:29:54 +02004335 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004336 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004337 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004338 }
4339
Michal Vasko07e89ef2016-03-03 13:28:57 +01004340 /* check augment target type and then augment nodes type */
Michal Vaskodb017262017-01-24 13:10:04 +01004341 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
4342 LY_TREE_FOR(aug->child, sub) {
4343 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4344 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4345 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4346 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4347 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
4348 return -1;
4349 }
4350 }
4351 } else if (aug_target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004352 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004353 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004354 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004355 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004356 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004357 return -1;
4358 }
4359 }
Michal Vasko15b36692016-08-26 15:29:54 +02004360 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004361 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004362 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004363 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004364 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004365 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004366 return -1;
4367 }
4368 }
4369 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004370 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko51e5c582017-01-19 14:16:39 +01004371 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004372 return -1;
4373 }
4374
Radek Krejcic071c542016-01-27 14:57:51 +01004375 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004376 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004377 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004378 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004379 }
4380 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004381
Michal Vasko15b36692016-08-26 15:29:54 +02004382 /* finally reconnect augmenting data into the target - add them to the target child list,
4383 * by setting aug->target we know the augment is fully resolved now */
4384 aug->target = (struct lys_node *)aug_target;
4385 if (aug->target->child) {
4386 sub = aug->target->child->prev; /* remember current target's last node */
4387 sub->next = aug->child; /* connect augmenting data after target's last node */
4388 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4389 aug->child->prev = sub; /* finish connecting of both child lists */
4390 } else {
4391 aug->target->child = aug->child;
4392 }
4393
Michal Vasko9e635ac2016-10-17 11:44:09 +02004394 /* inherit config information from actual parent */
4395 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4396 clear_config = (parent) ? 1 : 0;
4397 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004398 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004399 return -1;
4400 }
4401 }
4402
Radek Krejci80056d52017-01-05 13:13:33 +01004403 /* inherit extensions if any */
4404 for (u = 0; u < aug->target->ext_size; u++) {
4405 ext = aug->target->ext[u]; /* shortcut */
4406 if (ext && ext->def->plugin && (ext->def->plugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejcib08bc172017-02-27 13:17:14 +01004407 if (unres_schema_add_node(mod, unres, &ext, UNRES_EXT_FINALIZE, NULL) == -1) {
4408 /* something really bad happend since the extension finalization is not actually
4409 * being resolved while adding into unres, so something more serious with the unres
4410 * list itself must happened */
4411 return -1;
4412 }
Radek Krejci80056d52017-01-05 13:13:33 +01004413 }
4414 }
4415
Radek Krejci27fe55e2016-09-13 17:13:35 +02004416success:
4417 if (mod->implemented) {
4418 /* make target modules also implemented */
4419 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4420 if (lys_set_implemented(sub->module)) {
Radek Krejcib08bc172017-02-27 13:17:14 +01004421 LOGERR(ly_errno, "Setting the augmented module \"%s\" implemented failed.", sub->module->name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004422 return -1;
4423 }
4424 }
4425 }
4426
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004427 return EXIT_SUCCESS;
4428}
4429
Radek Krejcie534c132016-11-23 13:32:31 +01004430static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004431resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004432{
4433 enum LY_VLOG_ELEM vlog_type;
4434 void *vlog_node;
4435 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004436 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004437 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004438 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004439 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004440 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004441 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004442
4443 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004444 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004445 vlog_node = info->parent;
4446 vlog_type = LY_VLOG_LYS;
4447 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004448 case LYEXT_PAR_MODULE:
4449 case LYEXT_PAR_IMPORT:
4450 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004451 vlog_node = NULL;
4452 vlog_type = LY_VLOG_LYS;
4453 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004454 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004455 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004456 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004457 break;
4458 }
4459
4460 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004461 /* YIN */
4462
Radek Krejcie534c132016-11-23 13:32:31 +01004463 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004464 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004465 if (!mod) {
4466 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004467 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004468 }
4469
4470 /* find the extension definition */
4471 e = NULL;
4472 for (i = 0; i < mod->extensions_size; i++) {
4473 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4474 e = &mod->extensions[i];
4475 break;
4476 }
4477 }
4478 /* try submodules */
4479 for (j = 0; !e && j < mod->inc_size; j++) {
4480 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4481 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4482 e = &mod->inc[j].submodule->extensions[i];
4483 break;
4484 }
4485 }
4486 }
4487 if (!e) {
4488 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4489 return EXIT_FAILURE;
4490 }
4491
4492 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004493
Radek Krejci72b35992017-01-04 16:27:44 +01004494 if (e->plugin && e->plugin->check_position) {
4495 /* common part - we have plugin with position checking function, use it first */
4496 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4497 /* extension is not allowed here */
4498 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4499 return -1;
4500 }
4501 }
4502
Radek Krejci8d6b7422017-02-03 14:42:13 +01004503 /* extension type-specific part - allocation */
4504 if (e->plugin) {
4505 etype = e->plugin->type;
4506 } else {
4507 /* default type */
4508 etype = LYEXT_FLAG;
4509 }
4510 switch (etype) {
4511 case LYEXT_FLAG:
4512 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4513 break;
4514 case LYEXT_COMPLEX:
4515 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4516 break;
4517 case LYEXT_ERR:
4518 /* we never should be here */
4519 LOGINT;
4520 return -1;
4521 }
4522
4523 /* common part for all extension types */
4524 (*ext)->def = e;
4525 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004526 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004527 (*ext)->insubstmt = info->substmt;
4528 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004529 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004530
4531 if (!(e->flags & LYS_YINELEM) && e->argument) {
4532 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4533 if (!(*ext)->arg_value) {
4534 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4535 return -1;
4536 }
4537 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4538 }
4539
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004540 (*ext)->nodetype = LYS_EXT;
4541 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004542
Radek Krejci8d6b7422017-02-03 14:42:13 +01004543 /* extension type-specific part - parsing content */
4544 switch (etype) {
4545 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004546 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4547 if (!yin->ns) {
4548 /* garbage */
4549 lyxml_free(mod->ctx, yin);
4550 continue;
4551 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4552 /* standard YANG statements are not expected here */
4553 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4554 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004555 } else if (yin->ns == info->data.yin->ns &&
4556 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004557 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004558 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004559 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004560 return -1;
4561 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004562 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004563 yin->content = NULL;
4564 lyxml_free(mod->ctx, yin);
4565 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004566 /* extension instance */
4567 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4568 LYEXT_SUBSTMT_SELF, 0, unres)) {
4569 return -1;
4570 }
Radek Krejci72b35992017-01-04 16:27:44 +01004571
Radek Krejci72b35992017-01-04 16:27:44 +01004572 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004573 }
Radek Krejci72b35992017-01-04 16:27:44 +01004574 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004575 break;
4576 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004577 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004578 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4579 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004580 return -1;
4581 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004582 break;
4583 default:
4584 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004585 }
Radek Krejci72b35992017-01-04 16:27:44 +01004586
4587 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4588
Radek Krejcie534c132016-11-23 13:32:31 +01004589 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004590 /* YANG */
4591
PavolVicanc1807262017-01-31 18:00:27 +01004592 ext_prefix = (char *)(*ext)->def;
4593 tmp = strchr(ext_prefix, ':');
4594 if (!tmp) {
4595 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004596 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004597 }
4598 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004599
PavolVicanc1807262017-01-31 18:00:27 +01004600 /* get the module where the extension is supposed to be defined */
4601 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4602 if (!mod) {
4603 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4604 return EXIT_FAILURE;
4605 }
4606
4607 /* find the extension definition */
4608 e = NULL;
4609 for (i = 0; i < mod->extensions_size; i++) {
4610 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4611 e = &mod->extensions[i];
4612 break;
4613 }
4614 }
4615 /* try submodules */
4616 for (j = 0; !e && j < mod->inc_size; j++) {
4617 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4618 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4619 e = &mod->inc[j].submodule->extensions[i];
4620 break;
4621 }
4622 }
4623 }
4624 if (!e) {
4625 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4626 return EXIT_FAILURE;
4627 }
4628
4629 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4630
4631 if (e->plugin && e->plugin->check_position) {
4632 /* common part - we have plugin with position checking function, use it first */
4633 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4634 /* extension is not allowed here */
4635 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004636 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004637 }
4638 }
4639
PavolVican22e88682017-02-14 22:38:18 +01004640 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004641 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004642 (*ext)->def = e;
4643 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004644 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004645
PavolVicanb0d84102017-02-15 16:32:42 +01004646 if (e->argument && !(*ext)->arg_value) {
4647 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4648 goto error;
4649 }
4650
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004651 (*ext)->module = info->mod;
4652 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004653
PavolVican22e88682017-02-14 22:38:18 +01004654 /* extension type-specific part */
4655 if (e->plugin) {
4656 etype = e->plugin->type;
4657 } else {
4658 /* default type */
4659 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004660 }
PavolVican22e88682017-02-14 22:38:18 +01004661 switch (etype) {
4662 case LYEXT_FLAG:
4663 /* nothing change */
4664 break;
4665 case LYEXT_COMPLEX:
4666 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4667 if (!tmp_ext) {
4668 LOGMEM;
4669 goto error;
4670 }
4671 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4672 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004673 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004674 if (info->data.yang) {
4675 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004676 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4677 (struct lys_ext_instance_complex*)(*ext))) {
4678 goto error;
4679 }
4680 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4681 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004682 goto error;
4683 }
PavolVicana3876672017-02-21 15:49:51 +01004684 }
4685 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4686 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004687 }
PavolVican22e88682017-02-14 22:38:18 +01004688 break;
4689 case LYEXT_ERR:
4690 /* we never should be here */
4691 LOGINT;
4692 goto error;
4693 }
4694
PavolVican22e88682017-02-14 22:38:18 +01004695 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4696 goto error;
4697 }
4698 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004699 }
4700
4701 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004702error:
4703 free(ext_prefix);
4704 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004705}
4706
Michal Vasko730dfdf2015-08-11 14:48:05 +02004707/**
Pavol Vican855ca622016-09-05 13:07:54 +02004708 * @brief Resolve (find) choice default case. Does not log.
4709 *
4710 * @param[in] choic Choice to use.
4711 * @param[in] dflt Name of the default case.
4712 *
4713 * @return Pointer to the default node or NULL.
4714 */
4715static struct lys_node *
4716resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4717{
4718 struct lys_node *child, *ret;
4719
4720 LY_TREE_FOR(choic->child, child) {
4721 if (child->nodetype == LYS_USES) {
4722 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4723 if (ret) {
4724 return ret;
4725 }
4726 }
4727
4728 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004729 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004730 return child;
4731 }
4732 }
4733
4734 return NULL;
4735}
4736
4737/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004738 * @brief Resolve uses, apply augments, refines. Logs directly.
4739 *
Michal Vaskobb211122015-08-19 14:03:11 +02004740 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004741 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004742 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004743 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004744 */
Michal Vasko184521f2015-09-24 13:14:26 +02004745static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004746resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004747{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004748 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004749 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004750 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004751 struct lys_node_leaflist *llist;
4752 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004753 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004754 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004755 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004756 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004757 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004758 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004759
Michal Vasko71e1aa82015-08-12 12:17:51 +02004760 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004761
4762 /* HACK just check that the grouping is resolved
4763 * - the higher byte in flags is always empty in grouping (no flags there apply to the groupings)
4764 * so we use it to count unresolved uses inside the grouping */
4765#if __BYTE_ORDER == __LITTLE_ENDIAN
4766 assert(!((uint8_t*)&uses->grp->flags)[1]);
4767#else
4768 assert(!((uint8_t*)&uses->grp->flags)[0]);
4769#endif
Michal Vasko71e1aa82015-08-12 12:17:51 +02004770
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004771 if (!uses->grp->child) {
4772 /* grouping without children, warning was already displayed */
4773 return EXIT_SUCCESS;
4774 }
4775
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004776 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004777 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004778 if (node_aux->nodetype & LYS_GROUPING) {
4779 /* do not instantiate groupings from groupings */
4780 continue;
4781 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004782 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004783 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004784 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004785 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004786 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004787 }
Pavol Vican55abd332016-07-12 15:54:49 +02004788 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004789 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 +02004790 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004791 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004792 }
4793 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004794 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004795
Michal Vaskodef0db12015-10-07 13:22:48 +02004796 /* we managed to copy the grouping, the rest must be possible to resolve */
4797
Pavol Vican855ca622016-09-05 13:07:54 +02004798 if (uses->refine_size) {
4799 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4800 if (!refine_nodes) {
4801 LOGMEM;
4802 goto fail;
4803 }
4804 }
4805
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004806 /* apply refines */
4807 for (i = 0; i < uses->refine_size; i++) {
4808 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004809 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4810 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004811 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004812 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004813 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004814 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004815 }
4816
Radek Krejci1d82ef62015-08-07 14:44:40 +02004817 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004818 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004819 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004820 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004821 }
Pavol Vican855ca622016-09-05 13:07:54 +02004822 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004823
4824 /* description on any nodetype */
4825 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004826 lydict_remove(ctx, node->dsc);
4827 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828 }
4829
4830 /* reference on any nodetype */
4831 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004832 lydict_remove(ctx, node->ref);
4833 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004834 }
4835
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004836 /* config on any nodetype,
4837 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4838 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004839 node->flags &= ~LYS_CONFIG_MASK;
4840 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004841 }
4842
4843 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004844 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004845 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004846 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004847 leaf = (struct lys_node_leaf *)node;
4848
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004849 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004850 lydict_remove(ctx, leaf->dflt);
4851 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4852
4853 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004854 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4855 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004856 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004857 }
Radek Krejci200bf712016-08-16 17:11:04 +02004858 } else if (node->nodetype == LYS_LEAFLIST) {
4859 /* leaf-list */
4860 llist = (struct lys_node_leaflist *)node;
4861
4862 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004863 for (j = 0; j < llist->dflt_size; j++) {
4864 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004865 }
4866 free(llist->dflt);
4867
4868 /* copy the default set from refine */
4869 llist->dflt_size = rfn->dflt_size;
4870 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
Radek Krejci542ab142017-01-23 15:57:08 +01004871 for (j = 0; j < llist->dflt_size; j++) {
4872 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004873 }
4874
4875 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004876 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004877 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004878 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004879 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004880 }
4881 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004882 }
4883 }
4884
4885 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004886 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004887 /* remove current value */
4888 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004889
Radek Krejcibf285832017-01-26 16:05:41 +01004890 /* set new value */
4891 node->flags |= (rfn->flags & LYS_MAND_MASK);
4892
Pavol Vican855ca622016-09-05 13:07:54 +02004893 if (rfn->flags & LYS_MAND_TRUE) {
4894 /* check if node has default value */
4895 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004896 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4897 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004898 goto fail;
4899 }
4900 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004901 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4902 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004903 goto fail;
4904 }
4905 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004906 }
4907
4908 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004909 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4910 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4911 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004912 }
4913
4914 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004915 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004916 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004917 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004918 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004919 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004920 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004921 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004922 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004923 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004924 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004925 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004926 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004927 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004928 }
4929 }
4930
4931 /* must in leaf, leaf-list, list, container or anyxml */
4932 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004933 switch (node->nodetype) {
4934 case LYS_LEAF:
4935 old_size = &((struct lys_node_leaf *)node)->must_size;
4936 old_must = &((struct lys_node_leaf *)node)->must;
4937 break;
4938 case LYS_LEAFLIST:
4939 old_size = &((struct lys_node_leaflist *)node)->must_size;
4940 old_must = &((struct lys_node_leaflist *)node)->must;
4941 break;
4942 case LYS_LIST:
4943 old_size = &((struct lys_node_list *)node)->must_size;
4944 old_must = &((struct lys_node_list *)node)->must;
4945 break;
4946 case LYS_CONTAINER:
4947 old_size = &((struct lys_node_container *)node)->must_size;
4948 old_must = &((struct lys_node_container *)node)->must;
4949 break;
4950 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004951 case LYS_ANYDATA:
4952 old_size = &((struct lys_node_anydata *)node)->must_size;
4953 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004954 break;
4955 default:
4956 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004957 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004958 }
4959
4960 size = *old_size + rfn->must_size;
4961 must = realloc(*old_must, size * sizeof *rfn->must);
4962 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004963 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004964 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004965 }
Pavol Vican855ca622016-09-05 13:07:54 +02004966 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004967 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004968 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 +02004969 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004970 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4971 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4972 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4973 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4974 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004975 }
4976
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004977 *old_must = must;
4978 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004979
4980 /* check XPath dependencies again */
4981 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4982 goto fail;
4983 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004984 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004985
4986 /* if-feature in leaf, leaf-list, list, container or anyxml */
4987 if (rfn->iffeature_size) {
4988 old_size = &node->iffeature_size;
4989 old_iff = &node->iffeature;
4990
4991 size = *old_size + rfn->iffeature_size;
4992 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4993 if (!iff) {
4994 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004995 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004996 }
Pavol Vican855ca622016-09-05 13:07:54 +02004997 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4998 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004999 if (usize1) {
5000 /* there is something to duplicate */
5001 /* duplicate compiled expression */
5002 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
5003 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02005004 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005005
5006 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005007 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
5008 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005009 }
5010 }
5011
5012 *old_iff = iff;
5013 *old_size = size;
5014 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005015 }
5016
5017 /* apply augments */
5018 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01005019 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005020 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005021 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005022 }
5023 }
5024
Pavol Vican855ca622016-09-05 13:07:54 +02005025 /* check refines */
5026 for (i = 0; i < uses->refine_size; i++) {
5027 node = refine_nodes[i];
5028 rfn = &uses->refine[i];
5029
5030 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005031 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005032 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005033 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005034 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5035 (rfn->flags & LYS_CONFIG_W)) {
5036 /* setting config true under config false is prohibited */
5037 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01005038 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005039 "changing config from 'false' to 'true' is prohibited while "
5040 "the target's parent is still config 'false'.");
5041 goto fail;
5042 }
5043
5044 /* inherit config change to the target children */
5045 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5046 if (rfn->flags & LYS_CONFIG_W) {
5047 if (iter->flags & LYS_CONFIG_SET) {
5048 /* config is set explicitely, go to next sibling */
5049 next = NULL;
5050 goto nextsibling;
5051 }
5052 } else { /* LYS_CONFIG_R */
5053 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5054 /* error - we would have config data under status data */
5055 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01005056 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005057 "changing config from 'true' to 'false' is prohibited while the target "
5058 "has still a children with explicit config 'true'.");
5059 goto fail;
5060 }
5061 }
5062 /* change config */
5063 iter->flags &= ~LYS_CONFIG_MASK;
5064 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5065
5066 /* select next iter - modified LY_TREE_DFS_END */
5067 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5068 next = NULL;
5069 } else {
5070 next = iter->child;
5071 }
5072nextsibling:
5073 if (!next) {
5074 /* try siblings */
5075 next = iter->next;
5076 }
5077 while (!next) {
5078 /* parent is already processed, go to its sibling */
5079 iter = lys_parent(iter);
5080
5081 /* no siblings, go back through parents */
5082 if (iter == node) {
5083 /* we are done, no next element to process */
5084 break;
5085 }
5086 next = iter->next;
5087 }
5088 }
5089 }
5090
5091 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005092 if (rfn->dflt_size) {
5093 if (node->nodetype == LYS_CHOICE) {
5094 /* choice */
5095 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5096 rfn->dflt[0]);
5097 if (!((struct lys_node_choice *)node)->dflt) {
5098 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
5099 goto fail;
5100 }
5101 if (lyp_check_mandatory_choice(node)) {
5102 goto fail;
5103 }
Pavol Vican855ca622016-09-05 13:07:54 +02005104 }
5105 }
5106
5107 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005108 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005109 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005110 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5111 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005112 goto fail;
5113 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005114 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005115 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005116 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5117 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005118 goto fail;
5119 }
5120 }
5121
5122 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005123 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005124 if (node->nodetype == LYS_LEAFLIST) {
5125 llist = (struct lys_node_leaflist *)node;
5126 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005127 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5128 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005129 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5130 goto fail;
5131 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005132 } else if (node->nodetype == LYS_LEAF) {
5133 leaf = (struct lys_node_leaf *)node;
5134 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005135 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5136 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005137 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5138 goto fail;
5139 }
Pavol Vican855ca622016-09-05 13:07:54 +02005140 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005141
Pavol Vican855ca622016-09-05 13:07:54 +02005142 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005143 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005144 for (parent = node->parent;
5145 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5146 parent = parent->parent) {
5147 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5148 /* stop also on presence containers */
5149 break;
5150 }
5151 }
5152 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5153 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5154 if (lyp_check_mandatory_choice(parent)) {
5155 goto fail;
5156 }
5157 }
5158 }
5159 }
5160 free(refine_nodes);
5161
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005162 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005163
5164fail:
5165 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5166 lys_node_free(iter, NULL, 0);
5167 }
Pavol Vican855ca622016-09-05 13:07:54 +02005168 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005169 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005170}
5171
Radek Krejci83a4bac2017-02-07 15:53:04 +01005172void
5173resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005174{
5175 int i;
5176
5177 assert(der && base);
5178
Radek Krejci018f1f52016-08-03 16:01:20 +02005179 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005180 /* create a set for backlinks if it does not exist */
5181 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005182 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005183 /* store backlink */
5184 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005185
Radek Krejci85a54be2016-10-20 12:39:56 +02005186 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005187 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005188 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005189 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005190}
5191
Michal Vasko730dfdf2015-08-11 14:48:05 +02005192/**
5193 * @brief Resolve base identity recursively. Does not log.
5194 *
5195 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005196 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005197 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005198 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005199 *
Radek Krejci219fa612016-08-15 10:36:51 +02005200 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005201 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005202static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005203resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005204 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005205{
Michal Vaskof02e3742015-08-05 16:27:02 +02005206 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005207 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005208
Radek Krejcicf509982015-12-15 09:22:44 +01005209 assert(ret);
5210
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005211 /* search module */
5212 for (i = 0; i < module->ident_size; i++) {
5213 if (!strcmp(basename, module->ident[i].name)) {
5214
5215 if (!ident) {
5216 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005217 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005218 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005219 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005220 }
5221
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005222 base = &module->ident[i];
5223 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005224 }
5225 }
5226
5227 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005228 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5229 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5230 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005231
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005232 if (!ident) {
5233 *ret = &module->inc[j].submodule->ident[i];
5234 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005235 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005236
5237 base = &module->inc[j].submodule->ident[i];
5238 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005239 }
5240 }
5241 }
5242
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005243matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005244 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005245 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005246 /* is it already completely resolved? */
5247 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005248 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005249 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5250
5251 /* simple check for circular reference,
5252 * the complete check is done as a side effect of using only completely
5253 * resolved identities (previous check of unres content) */
5254 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5255 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5256 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005257 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005258 }
5259
Radek Krejci06f64ed2016-08-15 11:07:44 +02005260 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005261 }
5262 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005263
Radek Krejcibabbff82016-02-19 13:31:37 +01005264 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005265 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005266 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005267 }
5268
Radek Krejci219fa612016-08-15 10:36:51 +02005269 /* base not found (maybe a forward reference) */
5270 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005271}
5272
Michal Vasko730dfdf2015-08-11 14:48:05 +02005273/**
5274 * @brief Resolve base identity. Logs directly.
5275 *
5276 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005277 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005278 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005279 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005280 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005281 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005282 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005283 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005284static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005285resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005286 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005287{
5288 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005289 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005290 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005291 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005292 struct lys_module *mod;
5293
5294 assert((ident && !type) || (!ident && type));
5295
5296 if (!type) {
5297 /* have ident to resolve */
5298 ret = &target;
5299 flags = ident->flags;
5300 mod = ident->module;
5301 } else {
5302 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005303 ++type->info.ident.count;
5304 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5305 if (!type->info.ident.ref) {
5306 LOGMEM;
5307 return -1;
5308 }
5309
5310 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005311 flags = type->parent->flags;
5312 mod = type->parent->module;
5313 }
Michal Vaskof2006002016-04-21 16:28:15 +02005314 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005315
5316 /* search for the base identity */
5317 name = strchr(basename, ':');
5318 if (name) {
5319 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005320 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005321 name++;
5322
Michal Vasko2d851a92015-10-20 16:16:36 +02005323 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005324 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005325 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005326 }
5327 } else {
5328 name = basename;
5329 }
5330
Radek Krejcic071c542016-01-27 14:57:51 +01005331 /* get module where to search */
5332 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5333 if (!module) {
5334 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005335 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005336 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005337 }
5338
Radek Krejcic071c542016-01-27 14:57:51 +01005339 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005340 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5341 if (!rc) {
5342 assert(*ret);
5343
5344 /* check status */
5345 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5346 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5347 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005348 } else if (ident) {
5349 ident->base[ident->base_size++] = *ret;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005350
Radek Krejci83a4bac2017-02-07 15:53:04 +01005351 /* maintain backlinks to the derived identities */
5352 resolve_identity_backlink_update(ident, *ret);
Radek Krejci219fa612016-08-15 10:36:51 +02005353 }
5354 } else if (rc == EXIT_FAILURE) {
5355 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005356 if (type) {
5357 --type->info.ident.count;
5358 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005359 }
5360
Radek Krejci219fa612016-08-15 10:36:51 +02005361 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005362}
5363
Michal Vasko730dfdf2015-08-11 14:48:05 +02005364/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005365 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005366 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005367 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005368 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005369 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005370 *
5371 * @return Pointer to the identity resolvent, NULL on error.
5372 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005373struct lys_ident *
Radek Krejcia571d942017-02-24 09:26:49 +01005374resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005375{
Radek Krejci639491e2016-12-05 13:30:42 +01005376 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005377 int mod_name_len, rc, i;
5378 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005379 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005380
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005381 assert(type && ident_name && node);
5382
Michal Vaskof2d43962016-09-02 11:10:16 +02005383 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005384 return NULL;
5385 }
5386
Michal Vaskoc633ca02015-08-21 14:03:51 +02005387 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005388 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005389 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005390 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005391 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005392 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005393 return NULL;
5394 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005395 if (!mod_name) {
5396 /* no prefix, identity must be defined in the same module as node */
Radek Krejcia571d942017-02-24 09:26:49 +01005397 mod_name = lys_main_module(mod)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005398 mod_name_len = strlen(mod_name);
5399 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005400
Michal Vaskof2d43962016-09-02 11:10:16 +02005401 /* go through all the bases in all the derived types */
5402 while (type->der) {
5403 for (i = 0; i < type->info.ident.count; ++i) {
5404 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005405 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005406 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005407 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005408 goto match;
5409 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005410
Radek Krejci85a54be2016-10-20 12:39:56 +02005411 if (cur->der) {
5412 /* there are also some derived identities */
5413 for (u = 0; u < cur->der->number; u++) {
5414 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005415 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005416 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005417 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005418 /* we have match */
5419 cur = der;
5420 goto match;
5421 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005422 }
5423 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005424 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005425 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005426 }
5427
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005428 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005429 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005430
5431match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005432 for (i = 0; i < cur->iffeature_size; i++) {
5433 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005434 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005435 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 +02005436 return NULL;
5437 }
5438 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005439 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005440}
5441
Michal Vasko730dfdf2015-08-11 14:48:05 +02005442/**
Michal Vaskobb211122015-08-19 14:03:11 +02005443 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005444 *
Michal Vaskobb211122015-08-19 14:03:11 +02005445 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005446 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005447 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005448 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005449 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005450static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005451resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005452{
Michal Vasko51917552017-03-08 10:21:34 +01005453 int rc, endian_idx;
Radek Krejci010e54b2016-03-15 09:40:34 +01005454 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005455
Michal Vasko51917552017-03-08 10:21:34 +01005456#if __BYTE_ORDER == __LITTLE_ENDIAN
5457 endian_idx = 1;
5458#else
5459 endian_idx = 0;
5460#endif
5461
Radek Krejci6ff885d2017-01-03 14:06:22 +01005462 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
5463 * in some uses. When we see such a uses, the grouping's higher byte of the flags member (not used in
5464 * grouping) is used to store number of so far unresolved uses. The grouping cannot be used unless this
5465 * counter is decreased back to 0. To remember that the uses already increased grouping's counter, the
Radek Krejci010e54b2016-03-15 09:40:34 +01005466 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005467 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 +02005468
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005469 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005470 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5471 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005472 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005473 return -1;
5474 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005475 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005476 return -1;
5477 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005478 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005479 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5480 * (and smaller flags - it uses only a limited set of flags)
5481 */
Michal Vasko51917552017-03-08 10:21:34 +01005482 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005483 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005484 }
Michal Vasko92981a62016-10-14 10:25:16 +02005485 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005486 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005487 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005488 }
5489
Michal Vasko51917552017-03-08 10:21:34 +01005490 if (((uint8_t*)&uses->grp->flags)[endian_idx]) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005491 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005492 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005493 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005494 } else {
5495 /* instantiate grouping only when it is completely resolved */
5496 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005497 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005498 return EXIT_FAILURE;
5499 }
5500
Radek Krejci48464ed2016-03-17 15:44:09 +01005501 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005502 if (!rc) {
5503 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005504 if (par_grp && (uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005505 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005506 LOGINT;
5507 return -1;
5508 }
Michal Vasko51917552017-03-08 10:21:34 +01005509 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005510 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005511 }
Radek Krejcicf509982015-12-15 09:22:44 +01005512
5513 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005514 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005515 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005516 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005517 return -1;
5518 }
5519
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005520 return EXIT_SUCCESS;
5521 }
5522
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005523 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005524}
5525
Michal Vasko730dfdf2015-08-11 14:48:05 +02005526/**
Michal Vasko9957e592015-08-17 15:04:09 +02005527 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005528 *
Michal Vaskobb211122015-08-19 14:03:11 +02005529 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005530 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005531 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005532 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005533 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005534static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005535resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005536{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005537 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005538 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005539
5540 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005541 if (!list->child) {
5542 /* no child, possible forward reference */
5543 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5544 return EXIT_FAILURE;
5545 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005546 /* get the key name */
5547 if ((value = strpbrk(keys_str, " \t\n"))) {
5548 len = value - keys_str;
5549 while (isspace(value[0])) {
5550 value++;
5551 }
5552 } else {
5553 len = strlen(keys_str);
5554 }
5555
Michal Vasko0f99d3e2017-01-10 10:50:40 +01005556 rc = lys_get_data_sibling(lys_node_module((struct lys_node *)list), list->child, keys_str, len, LYS_LEAF,
5557 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005558 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005559 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5560 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005561 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005562
Radek Krejci48464ed2016-03-17 15:44:09 +01005563 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005564 /* check_key logs */
5565 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005566 }
5567
Radek Krejcicf509982015-12-15 09:22:44 +01005568 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005569 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005570 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5571 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005572 return -1;
5573 }
5574
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005575 /* prepare for next iteration */
5576 while (value && isspace(value[0])) {
5577 value++;
5578 }
5579 keys_str = value;
5580 }
5581
Michal Vaskof02e3742015-08-05 16:27:02 +02005582 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005583}
5584
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005585/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005586 * @brief Resolve (check) all must conditions of \p node.
5587 * Logs directly.
5588 *
5589 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005590 * @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 +02005591 *
5592 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5593 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005594static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005595resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005596{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005597 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005598 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005599 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005600 struct lys_restr *must;
5601 struct lyxp_set set;
5602
5603 assert(node);
5604 memset(&set, 0, sizeof set);
5605
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005606 if (inout_parent) {
5607 for (schema = lys_parent(node->schema);
5608 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5609 schema = lys_parent(schema));
5610 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5611 LOGINT;
5612 return -1;
5613 }
5614 must_size = ((struct lys_node_inout *)schema)->must_size;
5615 must = ((struct lys_node_inout *)schema)->must;
5616
Michal Vasko3cfa3182017-01-17 10:00:58 +01005617 node_flags = schema->flags;
5618
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005619 /* context node is the RPC/action */
5620 node = node->parent;
5621 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5622 LOGINT;
5623 return -1;
5624 }
5625 } else {
5626 switch (node->schema->nodetype) {
5627 case LYS_CONTAINER:
5628 must_size = ((struct lys_node_container *)node->schema)->must_size;
5629 must = ((struct lys_node_container *)node->schema)->must;
5630 break;
5631 case LYS_LEAF:
5632 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5633 must = ((struct lys_node_leaf *)node->schema)->must;
5634 break;
5635 case LYS_LEAFLIST:
5636 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5637 must = ((struct lys_node_leaflist *)node->schema)->must;
5638 break;
5639 case LYS_LIST:
5640 must_size = ((struct lys_node_list *)node->schema)->must_size;
5641 must = ((struct lys_node_list *)node->schema)->must;
5642 break;
5643 case LYS_ANYXML:
5644 case LYS_ANYDATA:
5645 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5646 must = ((struct lys_node_anydata *)node->schema)->must;
5647 break;
5648 case LYS_NOTIF:
5649 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5650 must = ((struct lys_node_notif *)node->schema)->must;
5651 break;
5652 default:
5653 must_size = 0;
5654 break;
5655 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005656
5657 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005658 }
5659
5660 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005661 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005662 return -1;
5663 }
5664
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005665 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005666
Michal Vasko8146d4c2016-05-09 15:50:29 +02005667 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005668 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005669 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5670 } else {
5671 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5672 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005673 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005674 }
5675 if (must[i].eapptag) {
5676 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5677 }
5678 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005679 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005680 }
5681 }
5682
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005683 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005684}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005685
Michal Vaskobf19d252015-10-08 15:39:17 +02005686/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005687 * @brief Resolve (find) when condition schema context node. Does not log.
5688 *
5689 * @param[in] schema Schema node with the when condition.
5690 * @param[out] ctx_snode When schema context node.
5691 * @param[out] ctx_snode_type Schema context node type.
5692 */
5693void
5694resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5695{
5696 const struct lys_node *sparent;
5697
5698 /* find a not schema-only node */
5699 *ctx_snode_type = LYXP_NODE_ELEM;
5700 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5701 if (schema->nodetype == LYS_AUGMENT) {
5702 sparent = ((struct lys_node_augment *)schema)->target;
5703 } else {
5704 sparent = schema->parent;
5705 }
5706 if (!sparent) {
5707 /* context node is the document root (fake root in our case) */
5708 if (schema->flags & LYS_CONFIG_W) {
5709 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5710 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005711 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005712 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005713 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005714 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005715 break;
5716 }
5717 schema = sparent;
5718 }
5719
5720 *ctx_snode = (struct lys_node *)schema;
5721}
5722
5723/**
Michal Vaskocf024702015-10-08 15:01:42 +02005724 * @brief Resolve (find) when condition context node. Does not log.
5725 *
5726 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005727 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005728 * @param[out] ctx_node Context node.
5729 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005730 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005731 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005732 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005733static int
5734resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5735 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005736{
Michal Vaskocf024702015-10-08 15:01:42 +02005737 struct lyd_node *parent;
5738 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005739 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005740 uint16_t i, data_depth, schema_depth;
5741
Michal Vasko508a50d2016-09-07 14:50:33 +02005742 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005743
Michal Vaskofe989752016-09-08 08:47:26 +02005744 if (node_type == LYXP_NODE_ELEM) {
5745 /* standard element context node */
5746 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5747 for (sparent = schema, schema_depth = 0;
5748 sparent;
5749 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5750 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5751 ++schema_depth;
5752 }
Michal Vaskocf024702015-10-08 15:01:42 +02005753 }
Michal Vaskofe989752016-09-08 08:47:26 +02005754 if (data_depth < schema_depth) {
5755 return -1;
5756 }
Michal Vaskocf024702015-10-08 15:01:42 +02005757
Michal Vasko956e8542016-08-26 09:43:35 +02005758 /* find the corresponding data node */
5759 for (i = 0; i < data_depth - schema_depth; ++i) {
5760 node = node->parent;
5761 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005762 if (node->schema != schema) {
5763 return -1;
5764 }
Michal Vaskofe989752016-09-08 08:47:26 +02005765 } else {
5766 /* root context node */
5767 while (node->parent) {
5768 node = node->parent;
5769 }
5770 while (node->prev->next) {
5771 node = node->prev;
5772 }
Michal Vaskocf024702015-10-08 15:01:42 +02005773 }
5774
Michal Vaskoa59495d2016-08-22 09:18:58 +02005775 *ctx_node = node;
5776 *ctx_node_type = node_type;
5777 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005778}
5779
Michal Vasko76c3bd32016-08-24 16:02:52 +02005780/**
5781 * @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 +01005782 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005783 *
5784 * @param[in] snode Schema node, whose children instances need to be unlinked.
5785 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5786 * it is moved to point to another sibling still in the original tree.
5787 * @param[in,out] ctx_node When context node, adjusted if needed.
5788 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5789 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5790 * Ordering may change, but there will be no semantic change.
5791 *
5792 * @return EXIT_SUCCESS on success, -1 on error.
5793 */
5794static int
5795resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5796 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5797{
5798 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005799 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005800
5801 switch (snode->nodetype) {
5802 case LYS_AUGMENT:
5803 case LYS_USES:
5804 case LYS_CHOICE:
5805 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005806 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005807 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005808 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5809 continue;
5810 }
5811
5812 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005813 return -1;
5814 }
5815 }
5816 break;
5817 case LYS_CONTAINER:
5818 case LYS_LIST:
5819 case LYS_LEAF:
5820 case LYS_LEAFLIST:
5821 case LYS_ANYXML:
5822 case LYS_ANYDATA:
5823 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5824 if (elem->schema == snode) {
5825
5826 if (elem == *ctx_node) {
5827 /* We are going to unlink our context node! This normally cannot happen,
5828 * but we use normal top-level data nodes for faking a document root node,
5829 * so if this is the context node, we just use the next top-level node.
5830 * Additionally, it can even happen that there are no top-level data nodes left,
5831 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5832 * lyxp_eval() can handle this special situation.
5833 */
5834 if (ctx_node_type == LYXP_NODE_ELEM) {
5835 LOGINT;
5836 return -1;
5837 }
5838
5839 if (elem->prev == elem) {
5840 /* unlinking last top-level element, use an empty data tree */
5841 *ctx_node = NULL;
5842 } else {
5843 /* in this case just use the previous/last top-level data node */
5844 *ctx_node = elem->prev;
5845 }
5846 } else if (elem == *node) {
5847 /* We are going to unlink the currently processed node. This does not matter that
5848 * much, but we would lose access to the original data tree, so just move our
5849 * pointer somewhere still inside it.
5850 */
5851 if ((*node)->prev != *node) {
5852 *node = (*node)->prev;
5853 } else {
5854 /* the processed node with sibings were all unlinked, oh well */
5855 *node = NULL;
5856 }
5857 }
5858
5859 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005860 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005861 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005862 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005863 LOGINT;
5864 return -1;
5865 }
5866 } else {
5867 *unlinked_nodes = elem;
5868 }
5869
5870 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5871 /* there can be only one instance */
5872 break;
5873 }
5874 }
5875 }
5876 break;
5877 default:
5878 LOGINT;
5879 return -1;
5880 }
5881
5882 return EXIT_SUCCESS;
5883}
5884
5885/**
5886 * @brief Relink the unlinked nodes back.
5887 *
5888 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5889 * we simply need a sibling from the original data tree.
5890 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5891 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5892 * or the sibling of \p unlinked_nodes.
5893 *
5894 * @return EXIT_SUCCESS on success, -1 on error.
5895 */
5896static int
5897resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5898{
5899 struct lyd_node *elem;
5900
5901 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005902 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005903 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005904 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005905 return -1;
5906 }
5907 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005908 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005909 return -1;
5910 }
5911 }
5912 }
5913
5914 return EXIT_SUCCESS;
5915}
5916
Radek Krejci03b71f72016-03-16 11:10:09 +01005917int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005918resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005919{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005920 int ret = 0;
5921 uint8_t must_size;
5922 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005923
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005924 assert(node);
5925
5926 schema = node->schema;
5927
5928 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005929 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005930 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005931 must_size = ((struct lys_node_container *)schema)->must_size;
5932 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005933 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005934 must_size = ((struct lys_node_leaf *)schema)->must_size;
5935 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005936 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005937 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5938 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005939 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005940 must_size = ((struct lys_node_list *)schema)->must_size;
5941 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005942 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005943 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005944 must_size = ((struct lys_node_anydata *)schema)->must_size;
5945 break;
5946 case LYS_NOTIF:
5947 must_size = ((struct lys_node_notif *)schema)->must_size;
5948 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005949 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005950 must_size = 0;
5951 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005952 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005953
5954 if (must_size) {
5955 ++ret;
5956 }
5957
5958 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5959 if (!node->prev->next) {
5960 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5961 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5962 ret += 0x2;
5963 }
5964 }
5965
5966 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005967}
5968
5969int
Radek Krejci46165822016-08-26 14:06:27 +02005970resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005971{
Radek Krejci46165822016-08-26 14:06:27 +02005972 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005973
Radek Krejci46165822016-08-26 14:06:27 +02005974 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005975
Radek Krejci46165822016-08-26 14:06:27 +02005976 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005977 return 1;
5978 }
5979
Radek Krejci46165822016-08-26 14:06:27 +02005980 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005981 goto check_augment;
5982
Radek Krejci46165822016-08-26 14:06:27 +02005983 while (parent) {
5984 /* stop conditions */
5985 if (!mode) {
5986 /* stop on node that can be instantiated in data tree */
5987 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5988 break;
5989 }
5990 } else {
5991 /* stop on the specified node */
5992 if (parent == stop) {
5993 break;
5994 }
5995 }
5996
5997 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005998 return 1;
5999 }
6000check_augment:
6001
6002 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006003 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006004 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006005 }
6006 parent = lys_parent(parent);
6007 }
6008
6009 return 0;
6010}
6011
Michal Vaskocf024702015-10-08 15:01:42 +02006012/**
6013 * @brief Resolve (check) all when conditions relevant for \p node.
6014 * Logs directly.
6015 *
6016 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02006017 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006018 * @return
6019 * -1 - error, ly_errno is set
6020 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02006021 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01006022 * 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 +02006023 */
Radek Krejci46165822016-08-26 14:06:27 +02006024int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006025resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02006026{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006027 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006028 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006029 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006030 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02006031 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006032
6033 assert(node);
6034 memset(&set, 0, sizeof set);
6035
Michal Vasko78d97e22017-02-21 09:54:38 +01006036 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006037 /* make the node dummy for the evaluation */
6038 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006039 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6040 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006041 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006042 if (rc) {
6043 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006044 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006045 }
Radek Krejci51093642016-03-29 10:14:59 +02006046 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006047 }
6048
Radek Krejci03b71f72016-03-16 11:10:09 +01006049 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006050 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006051 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006052 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006053 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006054 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6055 ((struct lys_node_container *)node->schema)->when->cond);
6056 } else {
6057 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
6058 goto cleanup;
6059 }
Michal Vaskocf024702015-10-08 15:01:42 +02006060 }
Radek Krejci51093642016-03-29 10:14:59 +02006061
6062 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006063 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006064 }
6065
Michal Vasko90fc2a32016-08-24 15:58:58 +02006066 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006067 goto check_augment;
6068
6069 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006070 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6071 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006072 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006073 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006074 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006075 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006076 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006077 }
6078 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006079
6080 unlinked_nodes = NULL;
6081 /* we do not want our node pointer to change */
6082 tmp_node = node;
6083 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6084 if (rc) {
6085 goto cleanup;
6086 }
6087
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006088 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6089 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006090
6091 if (unlinked_nodes && ctx_node) {
6092 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6093 rc = -1;
6094 goto cleanup;
6095 }
6096 }
6097
Radek Krejci03b71f72016-03-16 11:10:09 +01006098 if (rc) {
6099 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006100 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006101 }
Radek Krejci51093642016-03-29 10:14:59 +02006102 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006103 }
6104
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006105 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006106 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006107 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006108 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6109 ((struct lys_node_uses *)sparent)->when->cond);
6110 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006111 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006112 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6113 goto cleanup;
6114 }
Michal Vaskocf024702015-10-08 15:01:42 +02006115 }
Radek Krejci51093642016-03-29 10:14:59 +02006116
6117 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006118 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006119 }
6120
6121check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006122 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006123 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006124 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006125 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006126 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006127 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006128 }
6129 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006130
6131 unlinked_nodes = NULL;
6132 tmp_node = node;
6133 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6134 if (rc) {
6135 goto cleanup;
6136 }
6137
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006138 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6139 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006140
6141 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6142 * so the tree did not actually change and there is nothing for us to do
6143 */
6144 if (unlinked_nodes && ctx_node) {
6145 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6146 rc = -1;
6147 goto cleanup;
6148 }
6149 }
6150
Radek Krejci03b71f72016-03-16 11:10:09 +01006151 if (rc) {
6152 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006153 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006154 }
Radek Krejci51093642016-03-29 10:14:59 +02006155 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006156 }
6157
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006158 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006159 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006160 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006161 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006162 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006163 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006164 } else {
6165 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6166 goto cleanup;
6167 }
Michal Vaskocf024702015-10-08 15:01:42 +02006168 }
Radek Krejci51093642016-03-29 10:14:59 +02006169
6170 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006171 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006172 }
6173
Michal Vasko90fc2a32016-08-24 15:58:58 +02006174 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006175 }
6176
Radek Krejci0b7704f2016-03-18 12:16:14 +01006177 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006178
Radek Krejci51093642016-03-29 10:14:59 +02006179cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006180 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006181 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006182
Radek Krejci46165822016-08-26 14:06:27 +02006183 if (result) {
6184 if (node->when_status & LYD_WHEN_TRUE) {
6185 *result = 1;
6186 } else {
6187 *result = 0;
6188 }
6189 }
6190
Radek Krejci51093642016-03-29 10:14:59 +02006191 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006192}
6193
Radek Krejcicbb473e2016-09-16 14:48:32 +02006194static int
6195check_leafref_features(struct lys_type *type)
6196{
6197 struct lys_node *iter;
6198 struct ly_set *src_parents, *trg_parents, *features;
6199 unsigned int i, j, size, x;
6200 int ret = EXIT_SUCCESS;
6201
6202 assert(type->parent);
6203
6204 src_parents = ly_set_new();
6205 trg_parents = ly_set_new();
6206 features = ly_set_new();
6207
6208 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006209 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006210 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6211 continue;
6212 }
6213 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6214 }
6215 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006216 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006217 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6218 continue;
6219 }
6220 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6221 }
6222
6223 /* compare the features used in if-feature statements in the rest of both
6224 * chains of parents. The set of features used for target must be a subset
6225 * of features used for the leafref. This is not a perfect, we should compare
6226 * the truth tables but it could require too much resources, so we simplify that */
6227 for (i = 0; i < src_parents->number; i++) {
6228 iter = src_parents->set.s[i]; /* shortcut */
6229 if (!iter->iffeature_size) {
6230 continue;
6231 }
6232 for (j = 0; j < iter->iffeature_size; j++) {
6233 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6234 for (; size; size--) {
6235 if (!iter->iffeature[j].features[size - 1]) {
6236 /* not yet resolved feature, postpone this check */
6237 ret = EXIT_FAILURE;
6238 goto cleanup;
6239 }
6240 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6241 }
6242 }
6243 }
6244 x = features->number;
6245 for (i = 0; i < trg_parents->number; i++) {
6246 iter = trg_parents->set.s[i]; /* shortcut */
6247 if (!iter->iffeature_size) {
6248 continue;
6249 }
6250 for (j = 0; j < iter->iffeature_size; j++) {
6251 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6252 for (; size; size--) {
6253 if (!iter->iffeature[j].features[size - 1]) {
6254 /* not yet resolved feature, postpone this check */
6255 ret = EXIT_FAILURE;
6256 goto cleanup;
6257 }
6258 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6259 /* the feature is not present in features set of target's parents chain */
6260 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006261 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006262 "Leafref is not conditional based on \"%s\" feature as its target.",
6263 iter->iffeature[j].features[size - 1]->name);
6264 ret = -1;
6265 goto cleanup;
6266 }
6267 }
6268 }
6269 }
6270
6271cleanup:
6272 ly_set_free(features);
6273 ly_set_free(src_parents);
6274 ly_set_free(trg_parents);
6275
6276 return ret;
6277}
6278
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006279/**
Michal Vaskobb211122015-08-19 14:03:11 +02006280 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006281 *
6282 * @param[in] mod Main module.
6283 * @param[in] item Item to resolve. Type determined by \p type.
6284 * @param[in] type Type of the unresolved item.
6285 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006286 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006287 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006288 *
6289 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6290 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006291static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006292resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006293 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006294{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006295 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006296 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006297 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006298 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006299 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006300 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006301
Radek Krejcic79c6b12016-07-26 15:11:49 +02006302 struct ly_set *refs, *procs;
6303 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006304 struct lys_ident *ident;
6305 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006306 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006307 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006308 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006309 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006310 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006311 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006312 struct lys_ext_instance *ext, **extlist;
6313 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006314
6315 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006316 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006317 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006318 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006319 ident = item;
6320
Radek Krejci018f1f52016-08-03 16:01:20 +02006321 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006322 break;
6323 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006324 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006325 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006326 stype = item;
6327
Radek Krejci018f1f52016-08-03 16:01:20 +02006328 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006329 break;
6330 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006331 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006332 stype = item;
6333
Radek Krejci27fe55e2016-09-13 17:13:35 +02006334 if (!lys_node_module(node)->implemented) {
6335 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006336 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006337 rc = 0;
6338 break;
6339 }
Michal Vasko1c007172017-03-10 10:20:44 +01006340 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6341 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006342 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006343 /* check if leafref and its target are under a common if-features */
6344 rc = check_leafref_features(stype);
6345 if (rc) {
6346 break;
6347 }
6348
Radek Krejci46c4cd72016-01-21 15:13:52 +01006349 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006350 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6351 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006352 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006353 }
6354
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006355 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006356 case UNRES_TYPE_DER_EXT:
6357 parent_type++;
6358 /* no break */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006359 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006360 parent_type++;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006361 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006362 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006363 /* parent */
6364 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006365 stype = item;
6366
Michal Vasko88c29542015-11-27 14:57:53 +01006367 /* HACK type->der is temporarily unparsed type statement */
6368 yin = (struct lyxml_elem *)stype->der;
6369 stype->der = NULL;
6370
Pavol Vicana0e4e672016-02-24 12:20:04 +01006371 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6372 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006373 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006374
6375 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006376 /* may try again later */
6377 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006378 } else {
6379 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006380 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006381 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006382 }
6383
Michal Vasko88c29542015-11-27 14:57:53 +01006384 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006385 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006386 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006387 /* we need to always be able to free this, it's safe only in this case */
6388 lyxml_free(mod->ctx, yin);
6389 } else {
6390 /* may try again later, put all back how it was */
6391 stype->der = (struct lys_tpdf *)yin;
6392 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006393 }
Radek Krejcic13db382016-08-16 10:52:42 +02006394 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006395 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006396 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006397 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6398 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006399 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006400 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6401 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6402 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6403 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
Radek Krejci9b6aad22016-09-20 15:55:51 +02006404 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006405 * of the type's base member. */
6406 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6407 if (par_grp) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01006408#if __BYTE_ORDER == __LITTLE_ENDIAN
6409 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
6410#else
6411 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
6412#endif
Radek Krejci9b6aad22016-09-20 15:55:51 +02006413 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006414 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006415 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006416 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006417 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006418 iff_data = str_snode;
6419 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006420 if (!rc) {
6421 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006422 if (iff_data->infeature) {
6423 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6424 feat = *((struct lys_feature **)item);
6425 if (!feat->depfeatures) {
6426 feat->depfeatures = ly_set_new();
6427 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006428 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006429 }
6430 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006431 lydict_remove(mod->ctx, iff_data->fname);
6432 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006433 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006434 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006435 case UNRES_FEATURE:
6436 feat = (struct lys_feature *)item;
6437
6438 if (feat->iffeature_size) {
6439 refs = ly_set_new();
6440 procs = ly_set_new();
6441 ly_set_add(procs, feat, 0);
6442
6443 while (procs->number) {
6444 ref = procs->set.g[procs->number - 1];
6445 ly_set_rm_index(procs, procs->number - 1);
6446
6447 for (i = 0; i < ref->iffeature_size; i++) {
6448 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6449 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006450 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006451 if (ref->iffeature[i].features[j - 1] == feat) {
6452 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6453 goto featurecheckdone;
6454 }
6455
6456 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6457 k = refs->number;
6458 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6459 /* not yet seen feature, add it for processing */
6460 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6461 }
6462 }
6463 } else {
6464 /* forward reference */
6465 rc = EXIT_FAILURE;
6466 goto featurecheckdone;
6467 }
6468 }
6469
6470 }
6471 }
6472 rc = EXIT_SUCCESS;
6473
6474featurecheckdone:
6475 ly_set_free(refs);
6476 ly_set_free(procs);
6477 }
6478
6479 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006480 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006481 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006482 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006483 case UNRES_TYPEDEF_DFLT:
6484 parent_type++;
6485 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006486 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006487 stype = item;
6488
Radek Krejciab08f0f2017-03-09 16:37:15 +01006489 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006490 break;
6491 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006492 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006493 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006494 choic = item;
6495
Radek Krejcie00d2312016-08-12 15:27:49 +02006496 if (!choic->dflt) {
6497 choic->dflt = resolve_choice_dflt(choic, expr);
6498 }
Michal Vasko7955b362015-09-04 14:18:15 +02006499 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006500 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006501 } else {
6502 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006503 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006504 break;
6505 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006506 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006507 break;
6508 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006509 unique_info = (struct unres_list_uniq *)item;
6510 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006511 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006512 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006513 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006514 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006515 case UNRES_XPATH:
6516 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006517 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006518 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006519 case UNRES_EXT:
6520 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006521 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006522 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006523 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006524 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006525 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006526 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006527 if (eplugin) {
6528 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006529 u = malloc(sizeof *u);
6530 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006531 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6532 /* something really bad happend since the extension finalization is not actually
6533 * being resolved while adding into unres, so something more serious with the unres
6534 * list itself must happened */
6535 return -1;
6536 }
Radek Krejci80056d52017-01-05 13:13:33 +01006537 }
6538 }
Radek Krejci79685c92017-02-17 10:49:43 +01006539 }
6540 if (!rc || rc == -1) {
6541 /* cleanup on success or fatal error */
6542 if (ext_data->datatype == LYS_IN_YIN) {
6543 /* YIN */
6544 lyxml_free(mod->ctx, ext_data->data.yin);
6545 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006546 /* YANG */
6547 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006548 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006549 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006550 }
6551 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006552 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006553 u = (uint8_t *)str_snode;
6554 ext = (*(struct lys_ext_instance ***)item)[*u];
6555 free(u);
6556
Radek Krejci80056d52017-01-05 13:13:33 +01006557 eplugin = ext->def->plugin;
6558
6559 /* inherit */
6560 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6561 root = (struct lys_node *)ext->parent;
6562 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6563 LY_TREE_DFS_BEGIN(root->child, next, node) {
6564 /* first, check if the node already contain instance of the same extension,
6565 * in such a case we won't inherit. In case the node was actually defined as
6566 * augment data, we are supposed to check the same way also the augment node itself */
6567 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6568 goto inherit_dfs_sibling;
6569 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6570 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6571 goto inherit_dfs_sibling;
6572 }
6573
6574 if (eplugin->check_inherit) {
6575 /* we have a callback to check the inheritance, use it */
6576 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6577 case 0:
6578 /* yes - continue with the inheriting code */
6579 break;
6580 case 1:
6581 /* no - continue with the node's sibling */
6582 goto inherit_dfs_sibling;
6583 case 2:
6584 /* no, but continue with the children, just skip the inheriting code for this node */
6585 goto inherit_dfs_child;
6586 default:
6587 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6588 ext->def->module->name, ext->def->name, rc);
6589 }
6590 }
6591
6592 /* inherit the extension */
6593 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
6594 if (!extlist) {
6595 LOGMEM;
6596 return -1;
6597 }
6598 extlist[node->ext_size] = malloc(sizeof **extlist);
6599 if (!extlist[node->ext_size]) {
6600 LOGMEM;
6601 node->ext = extlist;
6602 return -1;
6603 }
6604 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6605 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6606
6607 node->ext = extlist;
6608 node->ext_size++;
6609
6610inherit_dfs_child:
6611 /* modification of - select element for the next run - children first */
6612 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6613 next = NULL;
6614 } else {
6615 next = node->child;
6616 }
6617 if (!next) {
6618inherit_dfs_sibling:
6619 /* no children, try siblings */
6620 next = node->next;
6621 }
6622 while (!next) {
6623 /* go to the parent */
6624 node = lys_parent(node);
6625
6626 /* we are done if we are back in the root (the starter's parent */
6627 if (node == root) {
6628 break;
6629 }
6630
6631 /* parent is already processed, go to its sibling */
6632 next = node->next;
6633 }
6634 }
6635 }
6636 }
6637
6638 /* final check */
6639 if (eplugin->check_result) {
6640 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006641 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006642 return -1;
6643 }
6644 }
6645
6646 rc = 0;
6647 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006648 default:
6649 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006650 break;
6651 }
6652
Radek Krejci54081ce2016-08-12 15:21:47 +02006653 if (has_str && !rc) {
6654 /* the string is no more needed in case of success.
6655 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006656 lydict_remove(mod->ctx, str_snode);
6657 }
6658
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006659 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006660}
6661
Michal Vaskof02e3742015-08-05 16:27:02 +02006662/* logs directly */
6663static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006664print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006665{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006666 struct lyxml_elem *xml;
6667 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006668 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006669 const char *name = NULL;
6670 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006671
Michal Vaskof02e3742015-08-05 16:27:02 +02006672 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006673 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006674 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006675 break;
6676 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006677 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006678 break;
6679 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006680 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6681 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006682 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006683 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006684 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006685 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006686 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6687 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006688 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006689 } else {
6690 LY_TREE_FOR(xml->attr, attr) {
6691 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006692 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006693 break;
6694 }
6695 }
6696 assert(attr);
6697 }
Radek Krejcie534c132016-11-23 13:32:31 +01006698 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006699 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006700 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006701 iff_data = str_node;
6702 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006703 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006704 case UNRES_FEATURE:
6705 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6706 ((struct lys_feature *)item)->name);
6707 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006708 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006709 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006710 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006711 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006712 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006713 if (str_node) {
6714 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6715 } /* else no default value in the type itself, but we are checking some restrictions against
6716 * possible default value of some base type. The failure is caused by not resolved base type,
6717 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006718 break;
6719 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006720 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006721 break;
6722 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006723 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006724 break;
6725 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006726 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006727 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006728 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006729 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6730 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006731 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006732 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006733 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6734 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006735 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006736 case UNRES_EXT:
6737 extinfo = (struct unres_ext *)str_node;
6738 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6739 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6740 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006741 default:
6742 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006743 break;
6744 }
6745}
6746
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006747/**
Michal Vaskobb211122015-08-19 14:03:11 +02006748 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006749 *
6750 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006751 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006752 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006753 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006754 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006755int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006756resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006757{
Radek Krejci010e54b2016-03-15 09:40:34 +01006758 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006759 struct lyxml_elem *yin;
6760 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006761 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006762
6763 assert(unres);
6764
Michal Vaskoe8734262016-09-29 14:12:06 +02006765 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006766 if (*ly_vlog_hide_location()) {
6767 log_hidden = 1;
6768 } else {
6769 log_hidden = 0;
6770 ly_vlog_hide(1);
6771 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006772
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006773 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006774 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006775 unres_count = 0;
6776 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006777
6778 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006779 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006780 * if-features are resolved here to make sure that we will have all if-features for
6781 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006782 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006783 continue;
6784 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006785 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006786 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006787
Michal Vasko88c29542015-11-27 14:57:53 +01006788 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006789 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 +02006790 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006791 unres->type[i] = UNRES_RESOLVED;
6792 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006793 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006794 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006795 if (!log_hidden) {
6796 ly_vlog_hide(0);
6797 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006798 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006799 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006800 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006801 } else {
6802 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006803 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006804 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006805 }
Michal Vasko88c29542015-11-27 14:57:53 +01006806 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006807
Michal Vasko88c29542015-11-27 14:57:53 +01006808 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006809 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006810 if (!log_hidden) {
6811 ly_vlog_hide(0);
6812 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006813
6814 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006815 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006816 continue;
6817 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006818 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 +01006819 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006820 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6821 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6822 yang =(struct yang_type *)yin;
6823 ((struct lys_type *)unres->item[i])->base = yang->base;
6824 if (yang->base == LY_TYPE_UNION) {
6825 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6826 }
6827 lydict_remove(mod->ctx, yang->name);
6828 free(yang);
6829 } else {
6830 lyxml_free(mod->ctx, yin);
6831 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006832 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006833 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006834 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006835 }
6836
Radek Krejci07d0fb92017-01-13 14:11:05 +01006837 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006838 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006839 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006840 continue;
6841 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006842
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006843 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 +01006844 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006845 if (unres->type[i] == UNRES_LIST_UNIQ) {
6846 /* free the allocated structure */
6847 free(unres->item[i]);
6848 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006849 unres->type[i] = UNRES_RESOLVED;
6850 ++resolved;
6851 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006852 if (!log_hidden) {
6853 ly_vlog_hide(0);
6854 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006855 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006856 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006857 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006858 } else {
6859 /* forward reference, erase ly_errno */
6860 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006861 }
6862 }
6863
Michal Vasko74a60c02017-03-08 10:19:48 +01006864 if (!log_hidden) {
6865 ly_vlog_hide(0);
6866 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006867
Radek Krejci80056d52017-01-05 13:13:33 +01006868 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6869 for (i = 0; i < unres->count; ++i) {
6870 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6871 continue;
6872 }
6873
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006874 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 +01006875 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006876 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006877 ++resolved;
6878 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006879 /* else error - it was already printed, but resolved was not increased,
6880 so this unres item will not be resolved again in the following code,
6881 but it will cause returning -1 at the end, this way we are able to
6882 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006883 }
6884
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006885 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006886 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6887 * all the validation errors
6888 */
6889 for (i = 0; i < unres->count; ++i) {
6890 if (unres->type[i] == UNRES_RESOLVED) {
6891 continue;
6892 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006893 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 +01006894 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006895 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006896 unres->type[i] = UNRES_RESOLVED;
6897 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006898 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006899 }
Radek Krejcib3142312016-11-09 11:04:12 +01006900 if (resolved < unres->count) {
6901 return -1;
6902 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006903 }
6904
Michal Vaskoe8734262016-09-29 14:12:06 +02006905 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006906 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006907 return EXIT_SUCCESS;
6908}
6909
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006910/**
Michal Vaskobb211122015-08-19 14:03:11 +02006911 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006912 *
6913 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006914 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006915 * @param[in] item Item to resolve. Type determined by \p type.
6916 * @param[in] type Type of the unresolved item.
6917 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006918 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006919 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006920 */
6921int
Radek Krejci48464ed2016-03-17 15:44:09 +01006922unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6923 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006924{
Radek Krejci54081ce2016-08-12 15:21:47 +02006925 int rc;
6926 const char *dictstr;
6927
6928 dictstr = lydict_insert(mod->ctx, str, 0);
6929 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6930
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006931 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006932 lydict_remove(mod->ctx, dictstr);
6933 }
6934 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006935}
6936
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006937/**
Michal Vaskobb211122015-08-19 14:03:11 +02006938 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006939 *
6940 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006941 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006942 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006943 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006944 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006945 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006946 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6947 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006948 */
6949int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006950unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006951 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006952{
Michal Vaskoef486d72016-09-27 12:10:44 +02006953 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006954 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006955
Michal Vasko9bf425b2015-10-22 11:42:03 +02006956 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6957 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006958
Michal Vasko9e862e82017-03-08 10:20:49 +01006959#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006960 uint32_t u;
6961
Radek Krejci850a5de2016-11-08 14:06:40 +01006962 /* check for duplicities in unres */
6963 for (u = 0; u < unres->count; u++) {
6964 if (unres->type[u] == type && unres->item[u] == item &&
6965 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006966 /* duplication, should not happen */
6967 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006968 }
6969 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006970#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006971
Radek Krejcic293bac2017-02-27 11:25:28 +01006972 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01006973 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01006974 rc = EXIT_FAILURE;
6975 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01006976 if (*ly_vlog_hide_location()) {
6977 log_hidden = 1;
6978 } else {
6979 log_hidden = 0;
6980 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006981 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006982 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006983 if (!log_hidden) {
6984 ly_vlog_hide(0);
6985 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006986
Radek Krejci80056d52017-01-05 13:13:33 +01006987 if (rc != EXIT_FAILURE) {
6988 if (rc == -1 && ly_errno == LY_EVALID) {
6989 ly_err_repeat();
6990 }
6991 if (type == UNRES_LIST_UNIQ) {
6992 /* free the allocated structure */
6993 free(item);
6994 } else if (rc == -1 && type == UNRES_IFFEAT) {
6995 /* free the allocated resources */
6996 free(*((char **)item));
6997 }
6998 return rc;
6999 } else {
7000 /* erase info about validation errors */
7001 ly_err_clean(1);
7002 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007003
Radek Krejci80056d52017-01-05 13:13:33 +01007004 print_unres_schema_item_fail(item, type, snode);
7005
7006 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7007 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7008 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7009 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7010 lyxml_unlink_elem(mod->ctx, yin, 1);
7011 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7012 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007013 }
Michal Vasko88c29542015-11-27 14:57:53 +01007014 }
7015
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007016 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007017 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
7018 if (!unres->item) {
7019 LOGMEM;
7020 return -1;
7021 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007022 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007023 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
7024 if (!unres->type) {
7025 LOGMEM;
7026 return -1;
7027 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007028 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007029 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
7030 if (!unres->str_snode) {
7031 LOGMEM;
7032 return -1;
7033 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007034 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007035 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
7036 if (!unres->module) {
7037 LOGMEM;
7038 return -1;
7039 }
7040 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007041
Michal Vasko3767fb22016-07-21 12:10:57 +02007042 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007043}
7044
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007045/**
Michal Vaskobb211122015-08-19 14:03:11 +02007046 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007047 *
7048 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007049 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007050 * @param[in] item Old item to be resolved.
7051 * @param[in] type Type of the old unresolved item.
7052 * @param[in] new_item New item to use in the duplicate.
7053 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007054 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007055 */
Michal Vaskodad19402015-08-06 09:51:53 +02007056int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007057unres_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 +02007058{
7059 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007060 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007061 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007062
Michal Vaskocf024702015-10-08 15:01:42 +02007063 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007064
Radek Krejcid09d1a52016-08-11 14:05:45 +02007065 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7066 if (type == UNRES_LIST_UNIQ) {
7067 aux_uniq.list = item;
7068 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7069 item = &aux_uniq;
7070 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007071 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007072
7073 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007074 if (type == UNRES_LIST_UNIQ) {
7075 free(new_item);
7076 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007077 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007078 }
7079
Radek Krejcic79c6b12016-07-26 15:11:49 +02007080 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007081 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007082 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007083 LOGINT;
7084 return -1;
7085 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007086 } else if (type == UNRES_IFFEAT) {
7087 /* duplicate unres_iffeature_data */
7088 iff_data = malloc(sizeof *iff_data);
7089 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7090 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7091 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7092 LOGINT;
7093 return -1;
7094 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007095 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007096 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007097 LOGINT;
7098 return -1;
7099 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007100 }
Michal Vaskodad19402015-08-06 09:51:53 +02007101
7102 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007103}
7104
Michal Vaskof02e3742015-08-05 16:27:02 +02007105/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007106int
Michal Vasko878e38d2016-09-05 12:17:53 +02007107unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007108{
Michal Vasko878e38d2016-09-05 12:17:53 +02007109 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007110 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007111
Radek Krejciddddd0d2017-01-20 15:20:46 +01007112 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007113 i = start_on_backwards;
7114 } else {
7115 i = unres->count - 1;
7116 }
7117 for (; i > -1; i--) {
7118 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007119 continue;
7120 }
7121 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007122 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007123 break;
7124 }
7125 } else {
7126 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7127 aux_uniq2 = (struct unres_list_uniq *)item;
7128 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007129 break;
7130 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007131 }
7132 }
7133
Michal Vasko878e38d2016-09-05 12:17:53 +02007134 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007135}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007136
Michal Vaskoede9c472016-06-07 09:38:15 +02007137static void
7138unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7139{
7140 struct lyxml_elem *yin;
7141 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007142 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007143
7144 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007145 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007146 case UNRES_TYPE_DER:
7147 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7148 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7149 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007150 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007151 lydict_remove(ctx, yang->name);
7152 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007153 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7154 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7155 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007156 } else {
7157 lyxml_free(ctx, yin);
7158 }
7159 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007160 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007161 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7162 lydict_remove(ctx, iff_data->fname);
7163 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007164 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007165 case UNRES_IDENT:
7166 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007167 case UNRES_CHOICE_DFLT:
7168 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007169 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7170 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007171 case UNRES_LIST_UNIQ:
7172 free(unres->item[i]);
7173 break;
PavolVicanc1807262017-01-31 18:00:27 +01007174 case UNRES_EXT:
7175 free(unres->str_snode[i]);
7176 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007177 default:
7178 break;
7179 }
7180 unres->type[i] = UNRES_RESOLVED;
7181}
7182
Michal Vasko88c29542015-11-27 14:57:53 +01007183void
Radek Krejcic071c542016-01-27 14:57:51 +01007184unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01007185{
7186 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007187 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007188
Radek Krejcic071c542016-01-27 14:57:51 +01007189 if (!unres || !(*unres)) {
7190 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007191 }
7192
Radek Krejcic071c542016-01-27 14:57:51 +01007193 assert(module || (*unres)->count == 0);
7194
7195 for (i = 0; i < (*unres)->count; ++i) {
7196 if ((*unres)->module[i] != module) {
7197 if ((*unres)->type[i] != UNRES_RESOLVED) {
7198 unresolved++;
7199 }
7200 continue;
7201 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007202
7203 /* free heap memory for the specific item */
7204 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007205 }
7206
Michal Vaskoede9c472016-06-07 09:38:15 +02007207 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01007208 if (!module || (!unresolved && !module->type)) {
7209 free((*unres)->item);
7210 free((*unres)->type);
7211 free((*unres)->str_snode);
7212 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007213 free((*unres));
7214 (*unres) = NULL;
7215 }
Michal Vasko88c29542015-11-27 14:57:53 +01007216}
7217
Michal Vasko3cfa3182017-01-17 10:00:58 +01007218static int
7219check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7220{
7221 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007222 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007223 char *buf;
7224
7225 for (op_node = lys_parent(sleaf);
7226 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7227 op_node = lys_parent(op_node));
7228
7229 if (op_node && lys_parent(op_node)) {
7230 /* nested operation - any absolute path is external */
7231 return 1;
7232 }
7233
7234 /* get the first node from the instid */
7235 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7236 if (!buf) {
7237 LOGMEM;
7238 return -1;
7239 }
7240
7241 /* there is a predicate, remove it */
7242 if (buf[strlen(buf) - 1] == ']') {
7243 assert(strchr(buf, '['));
7244 *strchr(buf, '[') = '\0';
7245 }
7246
7247 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01007248 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007249 if (!set || !set->number) {
7250 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007251 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007252 return 1;
7253 }
7254 free(buf);
7255
Michal Vasko3c777092017-01-17 14:10:09 +01007256 first_node = set->set.s[0];
7257 ly_set_free(set);
7258
Michal Vasko3cfa3182017-01-17 10:00:58 +01007259 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7260
7261 if (op_node) {
7262 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007263 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007264 assert(set->number == 1);
7265 return 0;
7266 } else {
7267 return 1;
7268 }
7269 }
7270
7271 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7272 * this itself), so we say it's not external */
7273 return 0;
7274}
7275
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007276/**
7277 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7278 *
7279 * @param[in] data Data node where the path is used
7280 * @param[in] path Instance-identifier node value.
7281 * @param[in,out] ret Resolved instance or NULL.
7282 *
7283 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7284 */
7285static int
7286resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7287{
7288 int i = 0, j;
7289 const struct lys_module *mod;
7290 struct ly_ctx *ctx = data->schema->module->ctx;
7291 const char *model, *name;
7292 char *str;
7293 int mod_len, name_len, has_predicate;
7294 struct unres_data node_match;
7295
7296 memset(&node_match, 0, sizeof node_match);
7297 *ret = NULL;
7298
7299 /* we need root to resolve absolute path */
7300 for (; data->parent; data = data->parent);
7301 /* we're still parsing it and the pointer is not correct yet */
7302 if (data->prev) {
7303 for (; data->prev->next; data = data->prev);
7304 }
7305
7306 /* search for the instance node */
7307 while (path[i]) {
7308 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7309 if (j <= 0) {
7310 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7311 goto error;
7312 }
7313 i += j;
7314
7315 str = strndup(model, mod_len);
7316 if (!str) {
7317 LOGMEM;
7318 goto error;
7319 }
7320 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007321 if (ctx->data_clb) {
7322 if (!mod) {
7323 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7324 } else if (!mod->implemented) {
7325 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7326 }
7327 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007328 free(str);
7329
Michal Vaskof53187d2017-01-13 13:23:14 +01007330 if (!mod || !mod->implemented || mod->disabled) {
7331 break;
7332 }
7333
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007334 if (resolve_data(mod, name, name_len, data, &node_match)) {
7335 /* no instance exists */
7336 break;
7337 }
7338
7339 if (has_predicate) {
7340 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1c007172017-03-10 10:20:44 +01007341 j = resolve_instid_predicate(&path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007342 if (j < 1) {
7343 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7344 goto error;
7345 }
7346 i += j;
7347
7348 if (!node_match.count) {
7349 /* no instance exists */
7350 break;
7351 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007352 } else if (node_match.count) {
7353 /* check that we are not addressing lists */
7354 for (j = 0; (unsigned)j < node_match.count; ++j) {
7355 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7356 unres_data_del(&node_match, j--);
7357 }
7358 }
7359 if (!node_match.count) {
7360 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7361 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007362 }
7363 }
7364
7365 if (!node_match.count) {
7366 /* no instance exists */
7367 if (req_inst > -1) {
7368 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7369 return EXIT_FAILURE;
7370 }
7371 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7372 return EXIT_SUCCESS;
7373 } else if (node_match.count > 1) {
7374 /* instance identifier must resolve to a single node */
7375 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7376 goto error;
7377 } else {
7378 /* we have required result, remember it and cleanup */
7379 *ret = node_match.node[0];
7380 free(node_match.node);
7381 return EXIT_SUCCESS;
7382 }
7383
7384error:
7385 /* cleanup */
7386 free(node_match.node);
7387 return -1;
7388}
7389
7390static int
7391resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007392{
Radek Krejci7de36cf2016-09-12 16:18:50 +02007393 struct unres_data matches;
7394 uint32_t i;
7395
Radek Krejci9b6aad22016-09-20 15:55:51 +02007396 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007397 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007398 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007399
7400 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007401 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007402 return -1;
7403 }
7404
7405 /* check that value matches */
7406 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007407 /* not that the value is already in canonical form since the parsers does the conversion,
7408 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007409 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007410 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007411 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007412 break;
7413 }
7414 }
7415
7416 free(matches.node);
7417
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007418 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007419 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007420 if (req_inst > -1) {
7421 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007422 return EXIT_FAILURE;
7423 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007424 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 +02007425 }
7426 }
7427
7428 return EXIT_SUCCESS;
7429}
7430
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007431/* 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 +01007432int
7433resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7434 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007435{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007436 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007437 struct lyd_node *ret;
7438 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007439 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007440
7441 assert(type->base == LY_TYPE_UNION);
7442
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007443 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7444 /* either NULL or instid previously converted to JSON */
7445 json_val = leaf->value.string;
7446 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007447
Michal Vaskofd6c6502017-01-06 12:15:41 +01007448 if (store) {
7449 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7450 free(leaf->value.bit);
7451 }
7452 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007453 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007454
7455 /* turn logging off, we are going to try to validate the value with all the types in order */
7456 hidden = *ly_vlog_hide_location();
7457 ly_vlog_hide(1);
7458
7459 t = NULL;
7460 found = 0;
7461 while ((t = lyp_get_next_union_type(type, t, &found))) {
7462 found = 0;
7463
7464 switch (t->base) {
7465 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007466 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7467 req_inst = -1;
7468 } else {
7469 req_inst = t->info.lref.req;
7470 }
7471
7472 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007473 if (store) {
7474 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7475 /* valid resolved */
7476 leaf->value.leafref = ret;
7477 leaf->value_type = LY_TYPE_LEAFREF;
7478 } else {
7479 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007480 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007481 return -1;
7482 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007483 }
7484 }
7485
7486 success = 1;
7487 }
7488 break;
7489 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007490 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7491 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7492 req_inst = -1;
7493 } else {
7494 req_inst = t->info.inst.req;
7495 }
7496
Michal Vaskod3a03112017-01-23 09:56:02 +01007497 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007498 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007499 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007500 /* valid resolved */
7501 leaf->value.instance = ret;
7502 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007503
Michal Vaskofd6c6502017-01-06 12:15:41 +01007504 if (json_val) {
7505 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7506 leaf->value_str = json_val;
7507 json_val = NULL;
7508 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007509 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007510 /* valid unresolved */
7511 if (json_val) {
7512 /* put the JSON val back */
7513 leaf->value.string = json_val;
7514 json_val = NULL;
7515 } else {
7516 leaf->value.instance = NULL;
7517 }
7518 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007519 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007520 }
7521
7522 success = 1;
7523 }
7524 break;
7525 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007526 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007527 success = 1;
7528 }
7529 break;
7530 }
7531
7532 if (success) {
7533 break;
7534 }
7535
7536 /* erase information about errors - they are false or irrelevant
7537 * and will be replaced by a single error messages */
7538 ly_err_clean(1);
7539
7540 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007541 if (store) {
7542 if (t->base == LY_TYPE_BITS) {
7543 free(leaf->value.bit);
7544 }
7545 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007546 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007547 }
7548
7549 /* turn logging back on */
7550 if (!hidden) {
7551 ly_vlog_hide(0);
7552 }
7553
7554 if (json_val) {
7555 if (!success) {
7556 /* put the value back for now */
7557 assert(leaf->value_type == LY_TYPE_UNION);
7558 leaf->value.string = json_val;
7559 } else {
7560 /* value was ultimately useless, but we could not have known */
7561 lydict_remove(leaf->schema->module->ctx, json_val);
7562 }
7563 }
7564
Michal Vaskofd6c6502017-01-06 12:15:41 +01007565 if (success) {
7566 if (resolved_type) {
7567 *resolved_type = t;
7568 }
7569 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007570 /* not found and it is required */
7571 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007572 return EXIT_FAILURE;
7573 }
7574
7575 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007576
Radek Krejci9b6aad22016-09-20 15:55:51 +02007577}
7578
Michal Vasko8bcdf292015-08-19 14:04:43 +02007579/**
7580 * @brief Resolve a single unres data item. Logs directly.
7581 *
Michal Vaskocf024702015-10-08 15:01:42 +02007582 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007583 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007584 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007585 *
7586 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7587 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007588int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007589resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007590{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007591 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007592 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007593 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007594 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007595
Michal Vasko83a6c462015-10-08 16:43:53 +02007596 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007597 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007598
Michal Vaskocf024702015-10-08 15:01:42 +02007599 switch (type) {
7600 case UNRES_LEAFREF:
7601 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007602 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007603 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7604 req_inst = -1;
7605 } else {
7606 req_inst = sleaf->type.info.lref.req;
7607 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007608 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7609 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007610 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007611 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007612 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7613 free(leaf->value.bit);
7614 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007615 leaf->value.leafref = ret;
7616 leaf->value_type = LY_TYPE_LEAFREF;
7617 } else {
7618 /* valid unresolved */
7619 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007620 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007621 return -1;
7622 }
7623 }
7624 }
7625 leaf->validity &= ~LYD_VAL_LEAFREF;
7626 } else {
7627 return rc;
7628 }
7629 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007630
Michal Vaskocf024702015-10-08 15:01:42 +02007631 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007632 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007633 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7634 if (ext_dep == -1) {
7635 return -1;
7636 }
7637
7638 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7639 req_inst = -1;
7640 } else {
7641 req_inst = sleaf->type.info.inst.req;
7642 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007643 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7644 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007645 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007646 /* valid resolved */
7647 leaf->value.instance = ret;
7648 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007649 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007650 /* valid unresolved */
7651 leaf->value.instance = NULL;
7652 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007653 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007654 } else {
7655 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007656 }
Michal Vaskocf024702015-10-08 15:01:42 +02007657 break;
7658
Radek Krejci7de36cf2016-09-12 16:18:50 +02007659 case UNRES_UNION:
7660 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007661 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007662
Michal Vaskocf024702015-10-08 15:01:42 +02007663 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007664 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007665 return rc;
7666 }
7667 break;
7668
Michal Vaskobf19d252015-10-08 15:39:17 +02007669 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007670 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007671 return rc;
7672 }
7673 break;
7674
7675 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007676 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007677 return rc;
7678 }
7679 break;
7680
Michal Vaskocf024702015-10-08 15:01:42 +02007681 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007682 LOGINT;
7683 return -1;
7684 }
7685
7686 return EXIT_SUCCESS;
7687}
7688
7689/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007690 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007691 *
7692 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007693 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007694 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007695 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007696 */
7697int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007698unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007699{
Radek Krejci03b71f72016-03-16 11:10:09 +01007700 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007701 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007702 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007703
Radek Krejci03b71f72016-03-16 11:10:09 +01007704 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007705 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7706 if (!unres->node) {
7707 LOGMEM;
7708 return -1;
7709 }
Michal Vaskocf024702015-10-08 15:01:42 +02007710 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007711 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7712 if (!unres->type) {
7713 LOGMEM;
7714 return -1;
7715 }
Michal Vaskocf024702015-10-08 15:01:42 +02007716 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007717
Radek Krejci0b7704f2016-03-18 12:16:14 +01007718 if (type == UNRES_WHEN) {
7719 /* remove previous result */
7720 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007721 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007722
7723 return EXIT_SUCCESS;
7724}
7725
7726/**
7727 * @brief Resolve every unres data item in the structure. Logs directly.
7728 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007729 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7730 * unresolved leafrefs/instids are accepted).
7731 *
7732 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7733 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007734 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007735 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7736 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007737 *
7738 * @return EXIT_SUCCESS on success, -1 on error.
7739 */
7740int
Radek Krejci082c84f2016-10-17 16:33:06 +02007741resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007742{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007743 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007744 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007745 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007746
Radek Krejci082c84f2016-10-17 16:33:06 +02007747 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007748 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007749
7750 if (!unres->count) {
7751 return EXIT_SUCCESS;
7752 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007753
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007754 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 +01007755 ignore_fail = 1;
7756 } else if (options & LYD_OPT_NOEXTDEPS) {
7757 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007758 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007759 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007760 }
7761
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007762 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007763 ly_vlog_hide(1);
7764
Radek Krejci0b7704f2016-03-18 12:16:14 +01007765 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007766 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007767 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007768 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007769 for (i = 0; i < unres->count; i++) {
Radek Krejci981a8ee2017-03-17 16:48:26 +01007770 if (unres->type[i] != UNRES_WHEN && unres->type[i] != UNRES_LEAFREF) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007771 continue;
7772 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007773 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007774 /* count when-stmt nodes in unres list */
7775 when_stmt++;
7776 }
7777
7778 /* resolve when condition only when all parent when conditions are already resolved */
7779 for (parent = unres->node[i]->parent;
7780 parent && LYD_WHEN_DONE(parent->when_status);
7781 parent = parent->parent) {
7782 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7783 /* the parent node was already unlinked, do not resolve this node,
7784 * it will be removed anyway, so just mark it as resolved
7785 */
7786 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7787 unres->type[i] = UNRES_RESOLVED;
7788 resolved++;
7789 break;
7790 }
7791 }
7792 if (parent) {
7793 continue;
7794 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007795
Michal Vasko3cfa3182017-01-17 10:00:58 +01007796 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007797 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007798 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007799 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007800 /* false when condition */
7801 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007802 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007803 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007804 } /* follows else */
7805
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007806 /* auto-delete */
7807 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7808 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7809
Radek Krejci0c0086a2016-03-24 15:20:28 +01007810 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7811 /* if it has parent non-presence containers that would be empty, we should actually
7812 * remove the container
7813 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007814 for (parent = unres->node[i];
7815 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7816 parent = parent->parent) {
7817 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7818 /* presence container */
7819 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007820 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007821 if (parent->next || parent->prev != parent) {
7822 /* non empty (the child we are in and we are going to remove is not the only child) */
7823 break;
7824 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007825 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007826 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007827
Radek Krejci0c0086a2016-03-24 15:20:28 +01007828 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007829 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007830 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007831
Radek Krejci0b7704f2016-03-18 12:16:14 +01007832 lyd_unlink(unres->node[i]);
7833 unres->type[i] = UNRES_DELETE;
7834 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007835
7836 /* update the rest of unres items */
7837 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007838 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007839 continue;
7840 }
7841
7842 /* test if the node is in subtree to be deleted */
7843 for (parent = unres->node[j]; parent; parent = parent->parent) {
7844 if (parent == unres->node[i]) {
7845 /* yes, it is */
7846 unres->type[j] = UNRES_RESOLVED;
7847 resolved++;
7848 break;
7849 }
7850 }
7851 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007852 } else {
7853 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007854 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007855 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007856 resolved++;
7857 progress = 1;
7858 } else if (rc == -1) {
7859 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007860 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007861 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007862 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007863 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007864 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007865 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007866 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007867
Radek Krejci0b7704f2016-03-18 12:16:14 +01007868 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007869 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007870 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007871 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007872 return -1;
7873 }
7874
7875 for (i = 0; del_items && i < unres->count; i++) {
7876 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7877 if (unres->type[i] != UNRES_DELETE) {
7878 continue;
7879 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007880 if (!unres->node[i]) {
7881 unres->type[i] = UNRES_RESOLVED;
7882 del_items--;
7883 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007884 }
7885
7886 /* really remove the complete subtree */
7887 lyd_free(unres->node[i]);
7888 unres->type[i] = UNRES_RESOLVED;
7889 del_items--;
7890 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007891 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007892
7893 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007894 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007895 if (unres->type[i] == UNRES_RESOLVED) {
7896 continue;
7897 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007898 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007899
Michal Vasko3cfa3182017-01-17 10:00:58 +01007900 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007901 if (rc) {
7902 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007903 return -1;
7904 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007905
7906 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007907 }
7908
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007909 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007910 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007911 return EXIT_SUCCESS;
7912}