blob: 8307a11be8644dc6a1f80bfa1b4f9aa7593ffcf1 [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;
Radek Krejcicc217a62016-04-08 16:58:11 +02001513 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001514
1515 assert(nodeid && start);
1516
1517 if (nodeid[0] == '/') {
1518 return NULL;
1519 }
1520
1521 str = p = strdup(nodeid);
1522 if (!str) {
1523 LOGMEM;
1524 return NULL;
1525 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001526
Michal Vasko3edeaf72016-02-11 13:17:43 +01001527 while (p) {
1528 token = p;
1529 p = strchr(p, '/');
1530 if (p) {
1531 *p = '\0';
1532 p++;
1533 }
1534
Radek Krejci5da4eb62016-04-08 14:45:51 +02001535 if (p) {
1536 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001537 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001538 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001539 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001540 result = NULL;
1541 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001542 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001543
Radek Krejci5da4eb62016-04-08 14:45:51 +02001544 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1545 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001546 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001547 /* shorthand case */
1548 if (!shorthand) {
1549 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001550 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001551 continue;
1552 } else {
1553 shorthand = 0;
1554 if (schema->nodetype == LYS_LEAF) {
1555 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1556 result = NULL;
1557 break;
1558 }
1559 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001560 }
1561 } else {
1562 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001563 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1564 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001565 || !schema) {
1566 result = NULL;
1567 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001568 }
1569 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001570 LY_TREE_FOR(result ? result->child : start, iter) {
1571 if (iter->schema == schema) {
1572 /* move in data tree according to returned schema */
1573 result = iter;
1574 break;
1575 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001576 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001577 if (!iter) {
1578 /* instance not found */
1579 result = NULL;
1580 break;
1581 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001582 }
1583 free(str);
1584
1585 return result;
1586}
1587
Radek Krejcibdf92362016-04-08 14:43:34 +02001588/*
1589 * 0 - ok (done)
1590 * 1 - continue
1591 * 2 - break
1592 * -1 - error
1593 */
1594static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001595schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001596 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001597 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001598{
1599 const struct lys_module *prefix_mod;
1600
1601 /* module check */
1602 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001603 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001604 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001605 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001606 if (!prefix_mod) {
1607 return -1;
1608 }
1609 if (prefix_mod != lys_node_module(sibling)) {
1610 return 1;
1611 }
1612
1613 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001614 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001615 if (*shorthand != -1) {
1616 *shorthand = *shorthand ? 0 : 1;
1617 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001618 }
1619
1620 /* the result node? */
1621 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001622 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001623 return 1;
1624 }
1625 return 0;
1626 }
1627
Radek Krejci3a130162016-11-07 16:21:20 +01001628 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001629 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001630 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001631 return -1;
1632 }
1633 *start = sibling->child;
1634 }
1635
1636 return 2;
1637}
1638
Radek Krejcidf46e222016-11-08 11:57:37 +01001639/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1640 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1641 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001642int
1643resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001644 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645{
Radek Krejcidf46e222016-11-08 11:57:37 +01001646 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001647 const struct lys_node *sibling;
1648 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001649 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001650 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001651 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001652
1653 assert(nodeid && (start || module) && !(start && module) && ret);
1654
1655 id = nodeid;
1656
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001657 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 +01001658 return ((id - nodeid) - r) + 1;
1659 }
1660 id += r;
1661
1662 if ((is_relative && !start) || (!is_relative && !module)) {
1663 return -1;
1664 }
1665
1666 /* descendant-schema-nodeid */
1667 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001668 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001669
1670 /* absolute-schema-nodeid */
1671 } else {
1672 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001673 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001674 /* if the submodule augments the mainmodule (or in general a module augments
1675 * itself, we don't want to search for the implemented module but augments
1676 * the module anyway. But when augmenting another module, we need the implemented
1677 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001678 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001679 if (!aux_mod->implemented && implement) {
1680 /* make the found module implemented */
1681 if (lys_set_implemented(aux_mod)) {
1682 return -1;
1683 }
1684 }
1685 start_mod = aux_mod;
1686 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001687 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001688 if (!start_mod) {
1689 return -1;
1690 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001691 start = start_mod->data;
1692 }
1693
1694 while (1) {
1695 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001696 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001697 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1698 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1699 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001700 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001701 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001702 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001703 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001704 *ret = sibling;
1705 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001706 } else if (r == 1) {
1707 continue;
1708 } else if (r == 2) {
1709 break;
1710 } else {
1711 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001712 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001713 }
1714 }
1715
1716 /* no match */
1717 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001718 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001719 return EXIT_SUCCESS;
1720 }
1721
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001722 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 +01001723 return ((id - nodeid) - r) + 1;
1724 }
1725 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001726
1727 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1728 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1729 /* we are getting into another module (augment) */
1730 if (implement) {
1731 /* we have to check that also target modules are implemented, if not, we have to change it */
1732 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1733 if (!aux_mod) {
1734 return -1;
1735 }
1736 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001737 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001738 if (!aux_mod->implemented) {
1739 /* make the found module implemented */
1740 if (lys_set_implemented(aux_mod)) {
1741 return -1;
1742 }
1743 }
1744 }
1745 } else {
1746 /* we are not implementing the module itself, so the augments outside the module are ignored */
1747 *ret = NULL;
1748 return EXIT_SUCCESS;
1749 }
1750 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001751 }
1752
1753 /* cannot get here */
1754 LOGINT;
1755 return -1;
1756}
1757
Radek Krejcif3c71de2016-04-11 12:45:46 +02001758/* unique, refine,
1759 * >0 - unexpected char on position (ret - 1),
1760 * 0 - ok (but ret can still be NULL),
1761 * -1 - error,
1762 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763int
1764resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001765 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001766{
1767 const char *name, *mod_name, *id;
1768 const struct lys_node *sibling;
1769 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001770 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001772 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001774 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001775 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001776
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001777 if (!start) {
1778 /* leaf not found */
1779 return 0;
1780 }
1781
Michal Vasko3edeaf72016-02-11 13:17:43 +01001782 id = nodeid;
1783 module = start->module;
1784
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001785 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001786 return ((id - nodeid) - r) + 1;
1787 }
1788 id += r;
1789
1790 if (!is_relative) {
1791 return -1;
1792 }
1793
1794 while (1) {
1795 sibling = NULL;
1796 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1797 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1798 /* name match */
1799 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001800 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001801 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001802 if (!(sibling->nodetype & ret_nodetype)) {
1803 /* wrong node type, too bad */
1804 continue;
1805 }
1806 *ret = sibling;
1807 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001808 } else if (r == 1) {
1809 continue;
1810 } else if (r == 2) {
1811 break;
1812 } else {
1813 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001814 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001815 }
1816 }
1817
1818 /* no match */
1819 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001820 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001821 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001822 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1823 *ret = NULL;
1824 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001825 }
1826
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001827 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 +01001828 return ((id - nodeid) - r) + 1;
1829 }
1830 id += r;
1831 }
1832
1833 /* cannot get here */
1834 LOGINT;
1835 return -1;
1836}
1837
1838/* choice default */
1839int
1840resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1841{
1842 /* cannot actually be a path */
1843 if (strchr(nodeid, '/')) {
1844 return -1;
1845 }
1846
Radek Krejcif3c71de2016-04-11 12:45:46 +02001847 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001848}
1849
1850/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1851static int
1852resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1853{
1854 const struct lys_module *module;
1855 const char *mod_prefix, *name;
1856 int i, mod_prefix_len, nam_len;
1857
1858 /* parse the identifier, it must be parsed on one call */
1859 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1860 return -i + 1;
1861 }
1862
1863 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1864 if (!module) {
1865 return -1;
1866 }
1867 if (module != start->module) {
1868 start = module->data;
1869 }
1870
1871 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1872
1873 return EXIT_SUCCESS;
1874}
1875
1876int
1877resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1878 const struct lys_node **ret)
1879{
1880 const char *name, *mod_name, *id;
1881 const struct lys_node *sibling, *start;
1882 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001883 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001884 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001885
1886 assert(nodeid && module && ret);
1887 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1888
1889 id = nodeid;
1890 start = module->data;
1891
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001892 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 +01001893 return ((id - nodeid) - r) + 1;
1894 }
1895 id += r;
1896
1897 if (is_relative) {
1898 return -1;
1899 }
1900
1901 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001902 if (!abs_start_mod) {
1903 return -1;
1904 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001905
1906 while (1) {
1907 sibling = NULL;
1908 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1909 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1910 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001911 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001912 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001913 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001914 if (!(sibling->nodetype & ret_nodetype)) {
1915 /* wrong node type, too bad */
1916 continue;
1917 }
1918 *ret = sibling;
1919 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001920 } else if (r == 1) {
1921 continue;
1922 } else if (r == 2) {
1923 break;
1924 } else {
1925 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001926 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001927 }
1928 }
1929
1930 /* no match */
1931 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001932 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001933 return EXIT_SUCCESS;
1934 }
1935
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001936 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 +01001937 return ((id - nodeid) - r) + 1;
1938 }
1939 id += r;
1940 }
1941
1942 /* cannot get here */
1943 LOGINT;
1944 return -1;
1945}
1946
Michal Vaskoe733d682016-03-14 09:08:27 +01001947static int
Michal Vasko3547c532016-03-14 09:40:50 +01001948resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001949{
1950 const char *name;
1951 int nam_len, has_predicate, i;
1952
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001953 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1954 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001955 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001956 return -1;
1957 }
1958
1959 predicate += i;
1960 *parsed += i;
1961
Michal Vasko58c2aab2017-01-05 10:02:05 +01001962 if (!isdigit(name[0])) {
1963 for (i = 0; i < list->keys_size; ++i) {
1964 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1965 break;
1966 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001967 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001968
Michal Vasko58c2aab2017-01-05 10:02:05 +01001969 if (i == list->keys_size) {
1970 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1971 return -1;
1972 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001973 }
1974
1975 /* more predicates? */
1976 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001977 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001978 }
1979
1980 return 0;
1981}
1982
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001983/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001984const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001985resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001986{
Michal Vasko10728b52016-04-07 14:26:29 +02001987 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001988 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001989 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001990 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001991 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001992 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001993
Michal Vasko3547c532016-03-14 09:40:50 +01001994 assert(nodeid && (ctx || start));
1995 if (!ctx) {
1996 ctx = start->module->ctx;
1997 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001998
1999 id = nodeid;
2000
Michal Vaskoe733d682016-03-14 09:08:27 +01002001 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 +01002002 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002003 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002004 }
2005 id += r;
2006
2007 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002008 assert(start);
2009 start = start->child;
2010 if (!start) {
2011 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002012 str = strndup(nodeid, (name + nam_len) - nodeid);
2013 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2014 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002015 return NULL;
2016 }
2017 module = start->module;
2018 } else {
2019 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002020 str = strndup(nodeid, (name + nam_len) - nodeid);
2021 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2022 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002023 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002024 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2025 LOGINT;
2026 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002027 }
2028
Michal Vasko971a3ca2016-04-01 13:09:29 +02002029 if (ly_buf_used && module_name[0]) {
2030 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2031 }
2032 ly_buf_used++;
2033
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002034 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002035 module_name[mod_name_len] = '\0';
2036 module = ly_ctx_get_module(ctx, module_name, NULL);
2037
2038 if (buf_backup) {
2039 /* return previous internal buffer content */
2040 strcpy(module_name, buf_backup);
2041 free(buf_backup);
2042 buf_backup = NULL;
2043 }
2044 ly_buf_used--;
2045
Michal Vasko3547c532016-03-14 09:40:50 +01002046 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002047 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2048 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2049 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002050 return NULL;
2051 }
2052 start = module->data;
2053
2054 /* now it's as if there was no module name */
2055 mod_name = NULL;
2056 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002057 }
2058
Michal Vaskoe733d682016-03-14 09:08:27 +01002059 prev_mod = module;
2060
Michal Vasko3edeaf72016-02-11 13:17:43 +01002061 while (1) {
2062 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002063 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2064 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002065 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002066 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002067 /* module check */
2068 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002069 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002070 LOGINT;
2071 return NULL;
2072 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002073
2074 if (ly_buf_used && module_name[0]) {
2075 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2076 }
2077 ly_buf_used++;
2078
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002079 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002080 module_name[mod_name_len] = '\0';
2081 /* will also find an augment module */
2082 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002083
2084 if (buf_backup) {
2085 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002086 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002087 free(buf_backup);
2088 buf_backup = NULL;
2089 }
2090 ly_buf_used--;
2091
Michal Vasko3edeaf72016-02-11 13:17:43 +01002092 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002093 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2094 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2095 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002096 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002097 }
2098 } else {
2099 prefix_mod = prev_mod;
2100 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002101 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002102 continue;
2103 }
2104
Michal Vaskoe733d682016-03-14 09:08:27 +01002105 /* do we have some predicates on it? */
2106 if (has_predicate) {
2107 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002108 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2109 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2110 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2111 return NULL;
2112 }
2113 } else if (sibling->nodetype == LYS_LIST) {
2114 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2115 return NULL;
2116 }
2117 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002118 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002119 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002120 }
2121 id += r;
2122 }
2123
Radek Krejcibdf92362016-04-08 14:43:34 +02002124 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002125 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002126 shorthand = ~shorthand;
2127 }
2128
Michal Vasko3edeaf72016-02-11 13:17:43 +01002129 /* the result node? */
2130 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002131 if (shorthand) {
2132 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002133 str = strndup(nodeid, (name + nam_len) - nodeid);
2134 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko51e5c582017-01-19 14:16:39 +01002135 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002136 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002137 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002138 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002139 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002140 }
2141
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002142 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002143 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002144 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002145 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002146 return NULL;
2147 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002148 start = sibling->child;
2149 }
2150
2151 /* update prev mod */
2152 prev_mod = start->module;
2153 break;
2154 }
2155 }
2156
2157 /* no match */
2158 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002159 str = strndup(nodeid, (name + nam_len) - nodeid);
2160 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2161 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002162 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002163 }
2164
Michal Vaskoe733d682016-03-14 09:08:27 +01002165 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 +01002166 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002167 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002168 }
2169 id += r;
2170 }
2171
2172 /* cannot get here */
2173 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002174 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002175}
2176
Michal Vasko22448d32016-03-16 13:17:29 +01002177static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002178resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2179 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002180{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002181 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002182 int nam_len, val_len, has_predicate = 1, r;
2183 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002184 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002185
Radek Krejci61a86c62016-03-24 11:06:44 +01002186 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002187 assert(node->schema->nodetype == LYS_LIST);
2188
Michal Vasko53adfc72017-01-06 10:39:10 +01002189 /* is the predicate a number? */
2190 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2191 || !strncmp(name, ".", nam_len)) {
2192 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2193 return -1;
2194 }
2195
2196 if (isdigit(name[0])) {
2197 if (position == atoi(name)) {
2198 /* match */
2199 *parsed += r;
2200 return 0;
2201 } else {
2202 /* not a match */
2203 return 1;
2204 }
2205 }
2206
2207 if (!((struct lys_node_list *)node->schema)->keys_size) {
2208 /* no keys in schema - causes an error later */
2209 return 0;
2210 }
2211
Michal Vaskof29903d2016-04-18 13:13:10 +02002212 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002213 if (!key) {
2214 /* it is not a position, so we need a key for it to be a match */
2215 return 1;
2216 }
2217
2218 /* go through all the keys */
2219 i = 0;
2220 goto check_parsed_values;
2221
2222 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002223 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002224 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002225 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002226 }
2227
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002228 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2229 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002230 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002231 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002232 }
2233
Michal Vasko53adfc72017-01-06 10:39:10 +01002234check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002235 predicate += r;
2236 *parsed += r;
2237
Michal Vaskof29903d2016-04-18 13:13:10 +02002238 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002239 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002240 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002241 }
2242
Michal Vasko9ba34de2016-12-07 12:21:19 +01002243 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002244 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002245 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2246 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002247 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2248 } else {
2249 key_val = key->value_str;
2250 }
2251
Michal Vasko22448d32016-03-16 13:17:29 +01002252 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002253 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002254 return 1;
2255 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002256
2257 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002258 }
2259
2260 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002261 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002262 return -1;
2263 }
2264
2265 return 0;
2266}
2267
Radek Krejci45826012016-08-24 15:07:57 +02002268/**
2269 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2270 *
2271 * @param[in] nodeid Node data path to find
2272 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2273 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2274 * @param[out] parsed Number of characters processed in \p id
2275 * @return The closes parent (or the node itself) from the path
2276 */
Michal Vasko22448d32016-03-16 13:17:29 +01002277struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002278resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2279 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002280{
Michal Vasko10728b52016-04-07 14:26:29 +02002281 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002282 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002283 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002284 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002285 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002286 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002287 const struct lys_module *prefix_mod, *prev_mod;
2288 struct ly_ctx *ctx;
2289
2290 assert(nodeid && start && parsed);
2291
2292 ctx = start->schema->module->ctx;
2293 id = nodeid;
2294
2295 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 +01002296 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002297 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002298 return NULL;
2299 }
2300 id += r;
2301 /* add it to parsed only after the data node was actually found */
2302 last_parsed = r;
2303
2304 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002305 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002306 start = start->child;
2307 } else {
2308 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002309 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002310 }
2311
2312 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002313 list_instance_position = 0;
2314
Michal Vasko22448d32016-03-16 13:17:29 +01002315 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002316 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002317 if (lys_parent(sibling->schema)) {
2318 if (options & LYD_PATH_OPT_OUTPUT) {
2319 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002320 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002321 *parsed = -1;
2322 return NULL;
2323 }
2324 } else {
2325 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002326 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002327 *parsed = -1;
2328 return NULL;
2329 }
2330 }
2331 }
2332
Michal Vasko22448d32016-03-16 13:17:29 +01002333 /* name match */
2334 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2335
2336 /* module check */
2337 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002338 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002339 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002340 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002341 return NULL;
2342 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002343
2344 if (ly_buf_used && module_name[0]) {
2345 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2346 }
2347 ly_buf_used++;
2348
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002349 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002350 module_name[mod_name_len] = '\0';
2351 /* will also find an augment module */
2352 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002353
2354 if (buf_backup) {
2355 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002356 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002357 free(buf_backup);
2358 buf_backup = NULL;
2359 }
2360 ly_buf_used--;
2361
Michal Vasko22448d32016-03-16 13:17:29 +01002362 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002363 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2364 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2365 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002366 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002367 return NULL;
2368 }
2369 } else {
2370 prefix_mod = prev_mod;
2371 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002372 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002373 continue;
2374 }
2375
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002376 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002377 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002378 llist = (struct lyd_node_leaf_list *)sibling;
2379
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002380 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002381 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002382 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 +02002383 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2384 *parsed = -1;
2385 return NULL;
2386 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002387 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2388 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2389 *parsed = -1;
2390 return NULL;
2391 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002392 } else {
2393 r = 0;
2394 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002395 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002396 }
2397 }
2398
Michal Vasko9ba34de2016-12-07 12:21:19 +01002399 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002400 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002401 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2402 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002403 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2404 } else {
2405 data_val = llist->value_str;
2406 }
2407
2408 if ((!llist_value && data_val && data_val[0])
2409 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002410 continue;
2411 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002412
Michal Vaskof0a50972016-10-19 11:33:55 +02002413 id += r;
2414 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002415 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002416
Radek Krejci45826012016-08-24 15:07:57 +02002417 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002418 /* 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 +01002419 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002420 /* none match */
2421 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002422 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002423
2424 ++list_instance_position;
2425 r = 0;
2426 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002427 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002428 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002429 return NULL;
2430 } else if (ret == 1) {
2431 /* this list instance does not match */
2432 continue;
2433 }
2434 id += r;
2435 last_parsed += r;
2436 }
2437
2438 *parsed += last_parsed;
2439
2440 /* the result node? */
2441 if (!id[0]) {
2442 return sibling;
2443 }
2444
2445 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002446 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002447 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002448 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002449 return NULL;
2450 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002451 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002452 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002453 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002454 break;
2455 }
2456 }
2457
2458 /* no match, return last match */
2459 if (!sibling) {
2460 return last_match;
2461 }
2462
2463 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 +01002464 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002465 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002466 return NULL;
2467 }
2468 id += r;
2469 last_parsed = r;
2470 }
2471
2472 /* cannot get here */
2473 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002474 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002475 return NULL;
2476}
2477
Michal Vasko3edeaf72016-02-11 13:17:43 +01002478/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002479 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002480 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002481 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002482 * @param[in] str_restr Restriction as a string.
2483 * @param[in] type Type of the restriction.
2484 * @param[out] ret Final interval structure that starts with
2485 * the interval of the initial type, continues with intervals
2486 * of any superior types derived from the initial one, and
2487 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002488 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002489 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002490 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002491int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002492resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002493{
2494 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002495 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002496 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002497 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002498 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002499 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002500 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002501
2502 switch (type->base) {
2503 case LY_TYPE_BINARY:
2504 kind = 0;
2505 local_umin = 0;
2506 local_umax = 18446744073709551615UL;
2507
2508 if (!str_restr && type->info.binary.length) {
2509 str_restr = type->info.binary.length->expr;
2510 }
2511 break;
2512 case LY_TYPE_DEC64:
2513 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002514 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2515 local_fmax = __INT64_C(9223372036854775807);
2516 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002517
2518 if (!str_restr && type->info.dec64.range) {
2519 str_restr = type->info.dec64.range->expr;
2520 }
2521 break;
2522 case LY_TYPE_INT8:
2523 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002524 local_smin = __INT64_C(-128);
2525 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002526
2527 if (!str_restr && type->info.num.range) {
2528 str_restr = type->info.num.range->expr;
2529 }
2530 break;
2531 case LY_TYPE_INT16:
2532 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002533 local_smin = __INT64_C(-32768);
2534 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002535
2536 if (!str_restr && type->info.num.range) {
2537 str_restr = type->info.num.range->expr;
2538 }
2539 break;
2540 case LY_TYPE_INT32:
2541 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002542 local_smin = __INT64_C(-2147483648);
2543 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002544
2545 if (!str_restr && type->info.num.range) {
2546 str_restr = type->info.num.range->expr;
2547 }
2548 break;
2549 case LY_TYPE_INT64:
2550 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002551 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2552 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002553
2554 if (!str_restr && type->info.num.range) {
2555 str_restr = type->info.num.range->expr;
2556 }
2557 break;
2558 case LY_TYPE_UINT8:
2559 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002560 local_umin = __UINT64_C(0);
2561 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002562
2563 if (!str_restr && type->info.num.range) {
2564 str_restr = type->info.num.range->expr;
2565 }
2566 break;
2567 case LY_TYPE_UINT16:
2568 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002569 local_umin = __UINT64_C(0);
2570 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002571
2572 if (!str_restr && type->info.num.range) {
2573 str_restr = type->info.num.range->expr;
2574 }
2575 break;
2576 case LY_TYPE_UINT32:
2577 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002578 local_umin = __UINT64_C(0);
2579 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002580
2581 if (!str_restr && type->info.num.range) {
2582 str_restr = type->info.num.range->expr;
2583 }
2584 break;
2585 case LY_TYPE_UINT64:
2586 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002587 local_umin = __UINT64_C(0);
2588 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002589
2590 if (!str_restr && type->info.num.range) {
2591 str_restr = type->info.num.range->expr;
2592 }
2593 break;
2594 case LY_TYPE_STRING:
2595 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002596 local_umin = __UINT64_C(0);
2597 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002598
2599 if (!str_restr && type->info.str.length) {
2600 str_restr = type->info.str.length->expr;
2601 }
2602 break;
2603 default:
2604 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002605 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002606 }
2607
2608 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002609 if (type->der) {
2610 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002611 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002612 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002613 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002614 assert(!intv || (intv->kind == kind));
2615 }
2616
2617 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002618 /* we do not have any restriction, return superior ones */
2619 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002620 return EXIT_SUCCESS;
2621 }
2622
2623 /* adjust local min and max */
2624 if (intv) {
2625 tmp_intv = intv;
2626
2627 if (kind == 0) {
2628 local_umin = tmp_intv->value.uval.min;
2629 } else if (kind == 1) {
2630 local_smin = tmp_intv->value.sval.min;
2631 } else if (kind == 2) {
2632 local_fmin = tmp_intv->value.fval.min;
2633 }
2634
2635 while (tmp_intv->next) {
2636 tmp_intv = tmp_intv->next;
2637 }
2638
2639 if (kind == 0) {
2640 local_umax = tmp_intv->value.uval.max;
2641 } else if (kind == 1) {
2642 local_smax = tmp_intv->value.sval.max;
2643 } else if (kind == 2) {
2644 local_fmax = tmp_intv->value.fval.max;
2645 }
2646 }
2647
2648 /* finally parse our restriction */
2649 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002650 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002651 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002652 if (!tmp_local_intv) {
2653 assert(!local_intv);
2654 local_intv = malloc(sizeof *local_intv);
2655 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002656 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002657 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002658 tmp_local_intv = tmp_local_intv->next;
2659 }
Michal Vasko253035f2015-12-17 16:58:13 +01002660 if (!tmp_local_intv) {
2661 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002662 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002663 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664
2665 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002666 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002667 tmp_local_intv->next = NULL;
2668
2669 /* min */
2670 ptr = seg_ptr;
2671 while (isspace(ptr[0])) {
2672 ++ptr;
2673 }
2674 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2675 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002676 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002677 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002678 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002679 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002680 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2681 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2682 goto error;
2683 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002684 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002685 } else if (!strncmp(ptr, "min", 3)) {
2686 if (kind == 0) {
2687 tmp_local_intv->value.uval.min = local_umin;
2688 } else if (kind == 1) {
2689 tmp_local_intv->value.sval.min = local_smin;
2690 } else if (kind == 2) {
2691 tmp_local_intv->value.fval.min = local_fmin;
2692 }
2693
2694 ptr += 3;
2695 } else if (!strncmp(ptr, "max", 3)) {
2696 if (kind == 0) {
2697 tmp_local_intv->value.uval.min = local_umax;
2698 } else if (kind == 1) {
2699 tmp_local_intv->value.sval.min = local_smax;
2700 } else if (kind == 2) {
2701 tmp_local_intv->value.fval.min = local_fmax;
2702 }
2703
2704 ptr += 3;
2705 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002706 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002707 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002708 }
2709
2710 while (isspace(ptr[0])) {
2711 ptr++;
2712 }
2713
2714 /* no interval or interval */
2715 if ((ptr[0] == '|') || !ptr[0]) {
2716 if (kind == 0) {
2717 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2718 } else if (kind == 1) {
2719 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2720 } else if (kind == 2) {
2721 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2722 }
2723 } else if (!strncmp(ptr, "..", 2)) {
2724 /* skip ".." */
2725 ptr += 2;
2726 while (isspace(ptr[0])) {
2727 ++ptr;
2728 }
2729
2730 /* max */
2731 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2732 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002733 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002734 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002735 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002736 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002737 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2738 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2739 goto error;
2740 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002741 }
2742 } else if (!strncmp(ptr, "max", 3)) {
2743 if (kind == 0) {
2744 tmp_local_intv->value.uval.max = local_umax;
2745 } else if (kind == 1) {
2746 tmp_local_intv->value.sval.max = local_smax;
2747 } else if (kind == 2) {
2748 tmp_local_intv->value.fval.max = local_fmax;
2749 }
2750 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002751 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002752 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002753 }
2754 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002755 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002756 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002757 }
2758
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002759 /* check min and max in correct order*/
2760 if (kind == 0) {
2761 /* current segment */
2762 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2763 goto error;
2764 }
2765 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2766 goto error;
2767 }
2768 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002769 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002770 goto error;
2771 }
2772 } else if (kind == 1) {
2773 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2774 goto error;
2775 }
2776 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2777 goto error;
2778 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002779 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002780 goto error;
2781 }
2782 } else if (kind == 2) {
2783 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2784 goto error;
2785 }
2786 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2787 goto error;
2788 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002789 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002790 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002791 goto error;
2792 }
2793 }
2794
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002795 /* next segment (next OR) */
2796 seg_ptr = strchr(seg_ptr, '|');
2797 if (!seg_ptr) {
2798 break;
2799 }
2800 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002801 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002802 }
2803
2804 /* check local restrictions against superior ones */
2805 if (intv) {
2806 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002807 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002808
2809 while (tmp_local_intv && tmp_intv) {
2810 /* reuse local variables */
2811 if (kind == 0) {
2812 local_umin = tmp_local_intv->value.uval.min;
2813 local_umax = tmp_local_intv->value.uval.max;
2814
2815 /* it must be in this interval */
2816 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2817 /* this interval is covered, next one */
2818 if (local_umax <= tmp_intv->value.uval.max) {
2819 tmp_local_intv = tmp_local_intv->next;
2820 continue;
2821 /* ascending order of restrictions -> fail */
2822 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002824 }
2825 }
2826 } else if (kind == 1) {
2827 local_smin = tmp_local_intv->value.sval.min;
2828 local_smax = tmp_local_intv->value.sval.max;
2829
2830 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2831 if (local_smax <= tmp_intv->value.sval.max) {
2832 tmp_local_intv = tmp_local_intv->next;
2833 continue;
2834 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002835 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002836 }
2837 }
2838 } else if (kind == 2) {
2839 local_fmin = tmp_local_intv->value.fval.min;
2840 local_fmax = tmp_local_intv->value.fval.max;
2841
Michal Vasko4d1f0482016-09-19 14:35:06 +02002842 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002843 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002844 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002845 tmp_local_intv = tmp_local_intv->next;
2846 continue;
2847 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002848 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002849 }
2850 }
2851 }
2852
2853 tmp_intv = tmp_intv->next;
2854 }
2855
2856 /* some interval left uncovered -> fail */
2857 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002858 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002859 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002860 }
2861
Michal Vaskoaeb51802016-04-11 10:58:47 +02002862 /* append the local intervals to all the intervals of the superior types, return it all */
2863 if (intv) {
2864 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2865 tmp_intv->next = local_intv;
2866 } else {
2867 intv = local_intv;
2868 }
2869 *ret = intv;
2870
2871 return EXIT_SUCCESS;
2872
2873error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002874 while (intv) {
2875 tmp_intv = intv->next;
2876 free(intv);
2877 intv = tmp_intv;
2878 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002879 while (local_intv) {
2880 tmp_local_intv = local_intv->next;
2881 free(local_intv);
2882 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002883 }
2884
Michal Vaskoaeb51802016-04-11 10:58:47 +02002885 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002886}
2887
Michal Vasko730dfdf2015-08-11 14:48:05 +02002888/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002889 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2890 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002891 *
2892 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002893 * @param[in] mod_name Typedef name module name.
2894 * @param[in] module Main module.
2895 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002896 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002897 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002898 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002899 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002900int
Michal Vasko1e62a092015-12-01 12:27:20 +01002901resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2902 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002903{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002904 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002905 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002906 int tpdf_size;
2907
Michal Vasko1dca6882015-10-22 14:29:42 +02002908 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002909 /* no prefix, try built-in types */
2910 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2911 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002912 if (ret) {
2913 *ret = ly_types[i].def;
2914 }
2915 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916 }
2917 }
2918 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002919 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002920 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002921 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002922 }
2923 }
2924
Michal Vasko1dca6882015-10-22 14:29:42 +02002925 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002926 /* search in local typedefs */
2927 while (parent) {
2928 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002929 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002930 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2931 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002932 break;
2933
Radek Krejci76512572015-08-04 09:47:08 +02002934 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002935 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2936 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937 break;
2938
Radek Krejci76512572015-08-04 09:47:08 +02002939 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002940 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2941 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002942 break;
2943
Radek Krejci76512572015-08-04 09:47:08 +02002944 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002945 case LYS_ACTION:
2946 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2947 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002948 break;
2949
Radek Krejci76512572015-08-04 09:47:08 +02002950 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002951 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2952 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002953 break;
2954
Radek Krejci76512572015-08-04 09:47:08 +02002955 case LYS_INPUT:
2956 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002957 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2958 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002959 break;
2960
2961 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002962 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002963 continue;
2964 }
2965
2966 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002967 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002968 match = &tpdf[i];
2969 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002970 }
2971 }
2972
Michal Vaskodcf98e62016-05-05 17:53:53 +02002973 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002974 }
Radek Krejcic071c542016-01-27 14:57:51 +01002975 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002976 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002977 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002978 if (!module) {
2979 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002980 }
2981 }
2982
2983 /* search in top level typedefs */
2984 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002985 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002986 match = &module->tpdf[i];
2987 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988 }
2989 }
2990
2991 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002992 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002993 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002994 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 +02002995 match = &module->inc[i].submodule->tpdf[j];
2996 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002997 }
2998 }
2999 }
3000
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003001 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003002
3003check_leafref:
3004 if (ret) {
3005 *ret = match;
3006 }
3007 if (match->type.base == LY_TYPE_LEAFREF) {
3008 while (!match->type.info.lref.path) {
3009 match = match->type.der;
3010 assert(match);
3011 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003012 }
3013 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003014}
3015
Michal Vasko1dca6882015-10-22 14:29:42 +02003016/**
3017 * @brief Check the default \p value of the \p type. Logs directly.
3018 *
3019 * @param[in] type Type definition to use.
3020 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003021 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003022 *
3023 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3024 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003025static int
Radek Krejci51673202016-11-01 17:00:32 +01003026check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027{
Radek Krejcibad2f172016-08-02 11:04:15 +02003028 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003029 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003030 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003031 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003032
Radek Krejci51673202016-11-01 17:00:32 +01003033 assert(value);
3034
Radek Krejcic13db382016-08-16 10:52:42 +02003035 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003036 /* the type was not resolved yet, nothing to do for now */
3037 return EXIT_FAILURE;
3038 }
3039
Radek Krejci51673202016-11-01 17:00:32 +01003040 dflt = *value;
3041 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003042 /* we do not have a new default value, so is there any to check even, in some base type? */
3043 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3044 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003045 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003046 break;
3047 }
3048 }
3049
Radek Krejci51673202016-11-01 17:00:32 +01003050 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003051 /* no default value, nothing to check, all is well */
3052 return EXIT_SUCCESS;
3053 }
3054
3055 /* 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)? */
3056 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003057 case LY_TYPE_IDENT:
3058 case LY_TYPE_INST:
3059 case LY_TYPE_LEAFREF:
3060 case LY_TYPE_BOOL:
3061 case LY_TYPE_EMPTY:
3062 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3063 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003064 case LY_TYPE_BITS:
3065 /* the default value must match the restricted list of values, if the type was restricted */
3066 if (type->info.bits.count) {
3067 break;
3068 }
3069 return EXIT_SUCCESS;
3070 case LY_TYPE_ENUM:
3071 /* the default value must match the restricted list of values, if the type was restricted */
3072 if (type->info.enums.count) {
3073 break;
3074 }
3075 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003076 case LY_TYPE_DEC64:
3077 if (type->info.dec64.range) {
3078 break;
3079 }
3080 return EXIT_SUCCESS;
3081 case LY_TYPE_BINARY:
3082 if (type->info.binary.length) {
3083 break;
3084 }
3085 return EXIT_SUCCESS;
3086 case LY_TYPE_INT8:
3087 case LY_TYPE_INT16:
3088 case LY_TYPE_INT32:
3089 case LY_TYPE_INT64:
3090 case LY_TYPE_UINT8:
3091 case LY_TYPE_UINT16:
3092 case LY_TYPE_UINT32:
3093 case LY_TYPE_UINT64:
3094 if (type->info.num.range) {
3095 break;
3096 }
3097 return EXIT_SUCCESS;
3098 case LY_TYPE_STRING:
3099 if (type->info.str.length || type->info.str.patterns) {
3100 break;
3101 }
3102 return EXIT_SUCCESS;
3103 case LY_TYPE_UNION:
3104 /* way too much trouble learning whether we need to check the default again, so just do it */
3105 break;
3106 default:
3107 LOGINT;
3108 return -1;
3109 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003110 } else if (type->base == LY_TYPE_EMPTY) {
3111 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3112 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3113 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003114 }
3115
Michal Vasko1dca6882015-10-22 14:29:42 +02003116 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003117 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003118 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003119 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003120 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003121 if (!node.schema) {
3122 LOGMEM;
3123 return -1;
3124 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003125 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003126 if (!node.schema->name) {
3127 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003128 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003129 return -1;
3130 }
Michal Vasko56826402016-03-02 11:11:37 +01003131 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003132 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003133
Radek Krejci37b756f2016-01-18 10:15:03 +01003134 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003135 if (!type->info.lref.target) {
3136 ret = EXIT_FAILURE;
3137 goto finish;
3138 }
Radek Krejci51673202016-11-01 17:00:32 +01003139 ret = check_default(&type->info.lref.target->type, &dflt, module);
3140 if (!ret) {
3141 /* adopt possibly changed default value to its canonical form */
3142 if (*value) {
3143 *value = dflt;
3144 }
3145 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003146 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003147 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003148 /* possible forward reference */
3149 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003150 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003151 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003152 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3153 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3154 /* we have refined bits/enums */
3155 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3156 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003157 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003158 }
3159 }
Radek Krejci51673202016-11-01 17:00:32 +01003160 } else {
3161 /* success - adopt canonical form from the node into the default value */
3162 if (dflt != node.value_str) {
3163 /* this can happen only if we have non-inherited default value,
3164 * inherited default values are already in canonical form */
3165 assert(dflt == *value);
3166 *value = node.value_str;
3167 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003168 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003169 }
3170
3171finish:
3172 if (node.value_type == LY_TYPE_BITS) {
3173 free(node.value.bit);
3174 }
3175 free((char *)node.schema->name);
3176 free(node.schema);
3177
3178 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003179}
3180
Michal Vasko730dfdf2015-08-11 14:48:05 +02003181/**
3182 * @brief Check a key for mandatory attributes. Logs directly.
3183 *
3184 * @param[in] key The key to check.
3185 * @param[in] flags What flags to check.
3186 * @param[in] list The list of all the keys.
3187 * @param[in] index Index of the key in the key list.
3188 * @param[in] name The name of the keys.
3189 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003190 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003191 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003192 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003193static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003194check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003195{
Radek Krejciadb57612016-02-16 13:34:34 +01003196 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003197 char *dup = NULL;
3198 int j;
3199
3200 /* existence */
3201 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003202 if (name[len] != '\0') {
3203 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003204 if (!dup) {
3205 LOGMEM;
3206 return -1;
3207 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003208 dup[len] = '\0';
3209 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003211 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003212 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003213 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003214 }
3215
3216 /* uniqueness */
3217 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003218 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003219 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003220 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003221 }
3222 }
3223
3224 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003225 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003226 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003227 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003228 }
3229
3230 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003231 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003232 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003233 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003234 }
3235
3236 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003237 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003238 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003239 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240 }
3241
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003242 /* key is not placed from augment */
3243 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003244 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003245 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003246 return -1;
3247 }
3248
Radek Krejci3f21ada2016-08-01 13:34:31 +02003249 /* key is not when/if-feature -conditional */
3250 j = 0;
3251 if (key->when || (key->iffeature_size && (j = 1))) {
3252 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003253 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003254 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003255 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003256 }
3257
Michal Vasko0b85aa82016-03-07 14:37:43 +01003258 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003259}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003260
3261/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003262 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003263 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003264 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003265 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003266 *
3267 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3268 */
3269int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003270resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271{
Radek Krejci581ce772015-11-10 17:22:40 +01003272 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003273 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003274
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003275 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003276 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003277 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003278 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003279 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003280 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003281 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003282 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003283 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003284 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003285 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003286 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003287 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003288 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003289 }
Radek Krejci581ce772015-11-10 17:22:40 +01003290 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003292 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003293 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003294 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003295 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003296 }
3297
Radek Krejcicf509982015-12-15 09:22:44 +01003298 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003299 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3300 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003301 return -1;
3302 }
3303
Radek Krejcid09d1a52016-08-11 14:05:45 +02003304 /* check that all unique's targets are of the same config type */
3305 if (*trg_type) {
3306 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3307 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003308 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003309 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3310 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3311 return -1;
3312 }
3313 } else {
3314 /* first unique */
3315 if (leaf->flags & LYS_CONFIG_W) {
3316 *trg_type = 1;
3317 } else {
3318 *trg_type = 2;
3319 }
3320 }
3321
Radek Krejcica7efb72016-01-18 13:06:01 +01003322 /* set leaf's unique flag */
3323 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3324
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003325 return EXIT_SUCCESS;
3326
3327error:
3328
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003329 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330}
3331
Radek Krejci0c0086a2016-03-24 15:20:28 +01003332void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003333unres_data_del(struct unres_data *unres, uint32_t i)
3334{
3335 /* there are items after the one deleted */
3336 if (i+1 < unres->count) {
3337 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003338 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003339
3340 /* deleting the last item */
3341 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003342 free(unres->node);
3343 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003344 }
3345
3346 /* if there are no items after and it is not the last one, just move the counter */
3347 --unres->count;
3348}
3349
Michal Vasko0491ab32015-08-19 14:28:29 +02003350/**
3351 * @brief Resolve (find) a data node from a specific module. Does not log.
3352 *
3353 * @param[in] mod Module to search in.
3354 * @param[in] name Name of the data node.
3355 * @param[in] nam_len Length of the name.
3356 * @param[in] start Data node to start the search from.
3357 * @param[in,out] parents Resolved nodes. If there are some parents,
3358 * they are replaced (!!) with the resolvents.
3359 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003360 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003361 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003362static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003363resolve_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 +02003364{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003365 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003366 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003367 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003368
Michal Vasko23b61ec2015-08-19 11:19:50 +02003369 if (!parents->count) {
3370 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003371 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003372 if (!parents->node) {
3373 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003374 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003375 }
Michal Vaskocf024702015-10-08 15:01:42 +02003376 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003379 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003381 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382 continue;
3383 }
3384 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003385 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003386 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3387 && node->schema->name[nam_len] == '\0') {
3388 /* matching target */
3389 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003390 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003391 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 flag = 1;
3393 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003394 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003395 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003396 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3397 if (!parents->node) {
3398 return EXIT_FAILURE;
3399 }
Michal Vaskocf024702015-10-08 15:01:42 +02003400 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003401 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
3403 }
3404 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003405
3406 if (!flag) {
3407 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003408 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003409 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003410 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003411 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 }
3413
Michal Vasko0491ab32015-08-19 14:28:29 +02003414 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003415}
3416
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003417/**
3418 * @brief Resolve (find) a data node. Does not log.
3419 *
Radek Krejci581ce772015-11-10 17:22:40 +01003420 * @param[in] mod_name Module name of the data node.
3421 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003422 * @param[in] name Name of the data node.
3423 * @param[in] nam_len Length of the name.
3424 * @param[in] start Data node to start the search from.
3425 * @param[in,out] parents Resolved nodes. If there are some parents,
3426 * they are replaced (!!) with the resolvents.
3427 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003428 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003429 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003430static int
Radek Krejci581ce772015-11-10 17:22:40 +01003431resolve_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 +02003432 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003433{
Michal Vasko1e62a092015-12-01 12:27:20 +01003434 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003435 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003436
Michal Vasko23b61ec2015-08-19 11:19:50 +02003437 assert(start);
3438
Michal Vasko31fc3672015-10-21 12:08:13 +02003439 if (mod_name) {
3440 /* we have mod_name, find appropriate module */
3441 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003442 if (!str) {
3443 LOGMEM;
3444 return -1;
3445 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003446 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3447 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003448 if (!mod) {
3449 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003450 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003451 }
3452 } else {
3453 /* no prefix, module is the same as of current node */
3454 mod = start->schema->module;
3455 }
3456
3457 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003458}
3459
Michal Vasko730dfdf2015-08-11 14:48:05 +02003460/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003461 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003462 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003463 *
Michal Vaskobb211122015-08-19 14:03:11 +02003464 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003465 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003466 * @param[in,out] node_match Nodes satisfying the restriction
3467 * without the predicate. Nodes not
3468 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003469 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003470 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003471 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003472 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003474resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003475 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003477 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003478 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003479 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003480 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3481 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003482 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003483 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003484
3485 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003486 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003487 if (!source_match.node) {
3488 LOGMEM;
3489 return -1;
3490 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003491 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003492 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003493 if (!dest_match.node) {
3494 LOGMEM;
3495 return -1;
3496 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003497
3498 do {
3499 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3500 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003501 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003502 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003503 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003505 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 pred += i;
3507
Michal Vasko23b61ec2015-08-19 11:19:50 +02003508 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003510 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003511
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003512 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003513 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003514 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003515 i = 0;
3516 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003517 }
3518
3519 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003520 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003521 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3523 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003524 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003525 rc = -1;
3526 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003528 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003529 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003530 dest_match.node[0] = dest_match.node[0]->parent;
3531 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003532 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003533 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003534 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003535 }
3536 }
3537 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003538 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003539 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003540 i = 0;
3541 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542 }
3543
3544 if (pke_len == pke_parsed) {
3545 break;
3546 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003547 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 +02003548 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003549 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003550 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003551 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552 }
3553 pke_parsed += i;
3554 }
3555
3556 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003557 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3558 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3559 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3560 }
3561 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3562 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3563 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3564 }
3565 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003566 goto remove_leafref;
3567 }
3568
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003569 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570 goto remove_leafref;
3571 }
3572
3573 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003574 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003575 continue;
3576
3577remove_leafref:
3578 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003579 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003580 }
3581 } while (has_predicate);
3582
Michal Vaskocf024702015-10-08 15:01:42 +02003583 free(source_match.node);
3584 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003585 if (parsed) {
3586 *parsed = parsed_loc;
3587 }
3588 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003589
3590error:
3591
3592 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003593 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003594 }
3595 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003596 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003597 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003598 if (parsed) {
3599 *parsed = -parsed_loc+i;
3600 }
3601 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003602}
3603
Michal Vasko730dfdf2015-08-11 14:48:05 +02003604/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003605 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003606 *
Michal Vaskocf024702015-10-08 15:01:42 +02003607 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003608 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003609 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003610 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003611 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003612 */
Michal Vasko184521f2015-09-24 13:14:26 +02003613static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003614resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615{
Radek Krejci71b795b2015-08-10 16:20:39 +02003616 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003617 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003618 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003619 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003620
Michal Vaskocf024702015-10-08 15:01:42 +02003621 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003622
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003624 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625
3626 /* searching for nodeset */
3627 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003628 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 +01003629 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003630 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003631 goto error;
3632 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003633 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003634 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003635
Michal Vasko23b61ec2015-08-19 11:19:50 +02003636 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003637 if (parent_times > 0) {
3638 data = node;
3639 for (i = 1; i < parent_times; ++i) {
3640 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003641 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003642 } else if (!parent_times) {
3643 data = node->child;
3644 } else {
3645 /* absolute path */
3646 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647 }
3648
Michal Vaskobfd98e62016-09-02 09:50:05 +02003649 /* we may still be parsing it and the pointer is not correct yet */
3650 if (data->prev) {
3651 while (data->prev->next) {
3652 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003653 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654 }
3655 }
3656
3657 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003658 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003659 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003660 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003661 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662 goto error;
3663 }
3664
3665 if (has_predicate) {
3666 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003667 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003668 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3669 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003670 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003671 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003672 continue;
3673 }
3674
3675 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003676 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003678 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003679 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003680 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003681 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682 goto error;
3683 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003685 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003686
Michal Vasko23b61ec2015-08-19 11:19:50 +02003687 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003688 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003689 goto error;
3690 }
3691 }
3692 } while (path[0] != '\0');
3693
Michal Vaskof02e3742015-08-05 16:27:02 +02003694 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695
3696error:
3697
Michal Vaskocf024702015-10-08 15:01:42 +02003698 free(ret->node);
3699 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003700 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003701
Michal Vasko0491ab32015-08-19 14:28:29 +02003702 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003703}
3704
Michal Vaskoe27516a2016-10-10 17:55:31 +00003705static int
3706resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3707{
3708 int dep1, dep2;
3709 const struct lys_node *node;
3710
3711 if (lys_parent(op_node)) {
3712 /* inner operation (notif/action) */
3713 if (abs_path) {
3714 return 1;
3715 } else {
3716 /* compare depth of both nodes */
3717 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3718 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3719 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3720 return 1;
3721 }
3722 }
3723 } else {
3724 /* top-level operation (notif/rpc) */
3725 if (op_node != first_node) {
3726 return 1;
3727 }
3728 }
3729
3730 return 0;
3731}
3732
Michal Vasko730dfdf2015-08-11 14:48:05 +02003733/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003734 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003735 *
Michal Vaskobb211122015-08-19 14:03:11 +02003736 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003737 * @param[in] context_node Predicate context node (where the predicate is placed).
3738 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003739 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003740 *
Michal Vasko184521f2015-09-24 13:14:26 +02003741 * @return 0 on forward reference, otherwise the number
3742 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003743 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003744 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003745static int
Radek Krejciadb57612016-02-16 13:34:34 +01003746resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003747 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003748{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003749 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003750 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003751 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003752 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3753 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003754
3755 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003756 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003757 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003758 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 return -parsed+i;
3760 }
3761 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003762 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003763
Michal Vasko58090902015-08-13 14:04:15 +02003764 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003765 if (sour_pref) {
3766 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3767 } else {
3768 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003769 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003770 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 +02003771 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003772 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003773 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003774 }
3775
3776 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003777 dest_parent_times = 0;
3778 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003779 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3780 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003781 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 +02003782 return -parsed;
3783 }
3784 pke_parsed += i;
3785
Radek Krejciadb57612016-02-16 13:34:34 +01003786 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003787 /* path is supposed to be evaluated in data tree, so we have to skip
3788 * all schema nodes that cannot be instantiated in data tree */
3789 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003790 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003791 dst_node = lys_parent(dst_node));
3792
Michal Vasko1f76a282015-08-04 16:16:53 +02003793 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003794 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003795 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003796 }
3797 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003798 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003799 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003800 if (dest_pref) {
3801 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3802 } else {
3803 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003804 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003805 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 +02003806 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003807 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003808 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 }
3810
Michal Vaskoe27516a2016-10-10 17:55:31 +00003811 if (first_iter) {
3812 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003813 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003814 }
3815 first_iter = 0;
3816 }
3817
Michal Vasko1f76a282015-08-04 16:16:53 +02003818 if (pke_len == pke_parsed) {
3819 break;
3820 }
3821
3822 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3823 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003824 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003825 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 return -parsed;
3827 }
3828 pke_parsed += i;
3829 }
3830
3831 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003832 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003833 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003834 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003835 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003836 return -parsed;
3837 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003838 } while (has_predicate);
3839
3840 return parsed;
3841}
3842
Michal Vasko730dfdf2015-08-11 14:48:05 +02003843/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003844 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003845 *
Michal Vaskobb211122015-08-19 14:03:11 +02003846 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003847 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003848 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3849 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003850 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003851 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003852 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003853 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003854static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003855resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003856 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003857{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003858 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003859 const struct lys_module *mod;
3860 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003861 const char *id, *prefix, *name;
3862 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003863 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003864
Michal Vasko184521f2015-09-24 13:14:26 +02003865 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003866 parent_times = 0;
3867 id = path;
3868
Michal Vaskoe27516a2016-10-10 17:55:31 +00003869 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003870 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003871 for (op_node = lys_parent(parent);
3872 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3873 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003874 }
3875
Radek Krejci990af1f2016-11-09 13:53:36 +01003876 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003877 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003878 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003879 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003880 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003881 }
3882 id += i;
3883
Michal Vasko184521f2015-09-24 13:14:26 +02003884 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003885 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003886 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003887 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3888 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003889 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3890 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003891 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003892 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003893 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003894 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003895 if (!mod->implemented) {
3896 /* make the found module implemented */
3897 if (lys_set_implemented(mod)) {
3898 return EXIT_FAILURE;
3899 }
3900 }
3901 }
3902 /* get start node */
3903 if (!mod->data) {
3904 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3905 "leafref", path);
3906 return EXIT_FAILURE;
3907 }
3908 node = mod->data;
3909
Michal Vasko1f76a282015-08-04 16:16:53 +02003910 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003911 if (parent_tpdf) {
3912 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003913 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003914 return -1;
3915 }
3916
Michal Vasko94458082016-10-07 14:34:36 +02003917 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3918 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003919 /* path is supposed to be evaluated in data tree, so we have to skip
3920 * all schema nodes that cannot be instantiated in data tree */
3921 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003922 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003923 node = lys_parent(node));
3924
Michal Vasko1f76a282015-08-04 16:16:53 +02003925 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003926 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003927 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003928 }
3929 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003930
3931 /* now we have to check that if we are going into a node from a different module,
3932 * the module is implemented (so its augments are applied) */
3933 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3934 if (!mod) {
3935 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3936 return EXIT_FAILURE;
3937 }
3938 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003939 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003940 if (!mod->implemented) {
3941 /* make the found module implemented */
3942 if (lys_set_implemented(mod)) {
3943 return EXIT_FAILURE;
3944 }
3945 }
3946 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003947 } else {
3948 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003949 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003950 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003951 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003952 /* we have to first check that the module we are going into is implemented */
3953 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3954 if (!mod) {
3955 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3956 return EXIT_FAILURE;
3957 }
3958 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003959 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003960 if (!mod->implemented) {
3961 /* make the found module implemented */
3962 if (lys_set_implemented(mod)) {
3963 return EXIT_FAILURE;
3964 }
3965 }
3966 }
3967
Michal Vasko7dc71d02016-03-15 10:42:28 +01003968 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003969 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003970 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003971 return -1;
3972 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003973 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003974 if (!node) {
3975 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3976 "leafref", path);
3977 return EXIT_FAILURE;
3978 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003979 }
3980
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003981 rc = lys_get_data_sibling(mod, node, name, nam_len, LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF
3982 | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003983 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003984 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003985 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003986 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003987
Michal Vaskoe27516a2016-10-10 17:55:31 +00003988 if (first_iter) {
3989 /* set external dependency flag, we can decide based on the first found node */
3990 if (!parent_tpdf && op_node && parent_times &&
3991 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003992 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003993 }
3994 first_iter = 0;
3995 }
3996
Michal Vasko1f76a282015-08-04 16:16:53 +02003997 if (has_predicate) {
3998 /* we have predicate, so the current result must be list */
3999 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004000 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004001 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004002 }
4003
Michal Vaskoe27516a2016-10-10 17:55:31 +00004004 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004005 if (i <= 0) {
4006 if (i == 0) {
4007 return EXIT_FAILURE;
4008 } else { /* i < 0 */
4009 return -1;
4010 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004011 }
4012 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004013 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004014 }
4015 } while (id[0]);
4016
Michal Vaskoca917682016-07-25 11:00:37 +02004017 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004018 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004019 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01004020 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 +02004021 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004022 }
4023
Radek Krejcicf509982015-12-15 09:22:44 +01004024 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004025 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004026 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004027 return -1;
4028 }
4029
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004030 if (ret) {
4031 *ret = node;
4032 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004033
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004034 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004035}
4036
Michal Vasko730dfdf2015-08-11 14:48:05 +02004037/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004038 * @brief Resolve instance-identifier predicate in JSON data format.
4039 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004040 *
Michal Vaskobb211122015-08-19 14:03:11 +02004041 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004042 * @param[in,out] node_match Nodes matching the restriction without
4043 * the predicate. Nodes not satisfying
4044 * the predicate are removed.
4045 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004046 * @return Number of characters successfully parsed,
4047 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004048 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004049static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004050resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004052 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004053 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004054 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004055 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004056 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004057
Michal Vasko1f2cc332015-08-19 11:18:32 +02004058 assert(pred && node_match->count);
4059
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004060 idx = -1;
4061 parsed = 0;
4062
Michal Vaskob2f40be2016-09-08 16:03:48 +02004063 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004065 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004066 return -parsed+i;
4067 }
4068 parsed += i;
4069 pred += i;
4070
4071 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004072 /* pos */
4073 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004074 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004075 } else if (name[0] != '.') {
4076 /* list keys */
4077 if (pred_iter < 0) {
4078 pred_iter = 1;
4079 } else {
4080 ++pred_iter;
4081 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 }
4083
Michal Vaskof2f28a12016-09-09 12:43:06 +02004084 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004086 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004087 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004088 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004089 goto remove_instid;
4090 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004091
4092 target = node_match->node[j];
4093 /* check the value */
4094 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4095 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4096 goto remove_instid;
4097 }
4098
4099 } else if (!value) {
4100 /* keyless list position */
4101 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4102 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4103 goto remove_instid;
4104 }
4105
4106 if (idx != cur_idx) {
4107 goto remove_instid;
4108 }
4109
4110 } else {
4111 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004112 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004113 goto remove_instid;
4114 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004115
4116 /* key module must match the list module */
4117 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4118 || node_match->node[j]->schema->module->name[mod_len]) {
4119 goto remove_instid;
4120 }
4121 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004122 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004123 if (!target) {
4124 goto remove_instid;
4125 }
4126 if ((struct lys_node_leaf *)target->schema !=
4127 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4128 goto remove_instid;
4129 }
4130
4131 /* check the value */
4132 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4133 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4134 goto remove_instid;
4135 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004136 }
4137
Michal Vaskob2f40be2016-09-08 16:03:48 +02004138 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004139 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004140 continue;
4141
4142remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004143 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004144 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004145 }
4146 } while (has_predicate);
4147
Michal Vaskob2f40be2016-09-08 16:03:48 +02004148 /* check that all list keys were specified */
4149 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004150 j = 0;
4151 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004152 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4153 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4154 /* not enough predicates, just remove the list instance */
4155 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004156 } else {
4157 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004158 }
4159 }
4160
4161 if (!node_match->count) {
4162 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4163 }
4164 }
4165
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004166 return parsed;
4167}
4168
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004169int
Michal Vasko769f8032017-01-24 13:11:55 +01004170lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004171{
4172 struct lys_node *parent, *elem;
4173 struct lyxp_set set;
4174 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004175 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004176
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004177 if (check_place) {
4178 parent = node;
4179 while (parent) {
4180 if (parent->nodetype == LYS_GROUPING) {
4181 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004182 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004183 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004184 if (parent->nodetype == LYS_AUGMENT) {
4185 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004186 /* unresolved augment */
4187 if (parent->module->implemented) {
4188 /* skip for now (will be checked later) */
4189 return EXIT_FAILURE;
4190 } else {
4191 /* not implemented augment, skip resolving */
4192 return EXIT_SUCCESS;
4193 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004194 } else {
4195 parent = ((struct lys_node_augment *)parent)->target;
4196 continue;
4197 }
4198 }
4199 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004200 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004201 }
4202
Michal Vasko769f8032017-01-24 13:11:55 +01004203 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4204 if (ret == -1) {
4205 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004206 }
4207
4208 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4209
4210 for (i = 0; i < set.used; ++i) {
4211 /* skip roots'n'stuff */
4212 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4213 /* XPath expression cannot reference "lower" status than the node that has the definition */
4214 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4215 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4216 return -1;
4217 }
4218
4219 if (parent) {
4220 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4221 if (!elem) {
4222 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004223 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004224 break;
4225 }
4226 }
4227 }
4228 }
4229
4230 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004231 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004232}
4233
Radek Krejcif71f48f2016-10-25 16:37:24 +02004234static int
4235check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4236{
4237 int i;
4238
4239 if (type->base == LY_TYPE_LEAFREF) {
4240 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4241 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4242 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4243 return -1;
4244 }
4245 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4246 * of leafref resolving (lys_leaf_add_leafref_target()) */
4247 } else if (type->base == LY_TYPE_UNION) {
4248 for (i = 0; i < type->info.uni.count; i++) {
4249 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4250 return -1;
4251 }
4252 }
4253 }
4254 return 0;
4255}
4256
Michal Vasko9e635ac2016-10-17 11:44:09 +02004257/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004258 * @brief Passes config flag down to children, skips nodes without config flags.
4259 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004260 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004261 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004262 * @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 +02004263 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004264 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004265 *
4266 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004267 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004268static int
Radek Krejcib3142312016-11-09 11:04:12 +01004269inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004270{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004271 struct lys_node_leaf *leaf;
4272
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004273 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004274 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004275 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004276 return -1;
4277 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004278 if (clear) {
4279 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004280 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004281 } else {
4282 if (node->flags & LYS_CONFIG_SET) {
4283 /* skip nodes with an explicit config value */
4284 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4285 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004286 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004287 return -1;
4288 }
4289 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004290 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004291
4292 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4293 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4294 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004295 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4296 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004297 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4298 return -1;
4299 }
4300 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004301 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004302 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004303 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004304 return -1;
4305 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004306 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4307 leaf = (struct lys_node_leaf *)node;
4308 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004309 return -1;
4310 }
4311 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004312 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004313
4314 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004315}
4316
Michal Vasko730dfdf2015-08-11 14:48:05 +02004317/**
Michal Vasko7178e692016-02-12 15:58:05 +01004318 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004319 *
Michal Vaskobb211122015-08-19 14:03:11 +02004320 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004321 * @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 +01004322 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004323 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004324 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004325 */
Michal Vasko7178e692016-02-12 15:58:05 +01004326static int
Radek Krejcib3142312016-11-09 11:04:12 +01004327resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004328{
Michal Vaskoe022a562016-09-27 14:24:15 +02004329 int rc, clear_config;
Radek Krejci80056d52017-01-05 13:13:33 +01004330 unsigned int u;
Michal Vasko1d87a922015-08-21 12:57:16 +02004331 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004332 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004333 struct lys_module *mod;
Radek Krejci80056d52017-01-05 13:13:33 +01004334 struct lys_ext_instance *ext;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004335
Michal Vasko15b36692016-08-26 15:29:54 +02004336 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004337 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004338
Michal Vasko15b36692016-08-26 15:29:54 +02004339 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004340 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004341 if (rc == -1) {
4342 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004343 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004344 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4345 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004346 } else if (rc == 0 && aug->target) {
4347 /* augment was resolved as a side effect of setting module implemented when
4348 * resolving augment schema nodeid, so we are done here */
4349 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004350 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004351 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004352 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4353 return EXIT_FAILURE;
4354 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004355 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004356 if (!mod->implemented) {
4357 /* it must be augment only to the same module,
4358 * otherwise we do not apply augment in not-implemented
4359 * module. If the module is set to be implemented in future,
4360 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004361 if (!aug_target) {
4362 /* target was not even resolved */
4363 return EXIT_SUCCESS;
4364 }
4365 /* target was resolved, but it may refer another module */
4366 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004367 if (lys_node_module(sub) != mod) {
4368 /* this is not an implemented module and the augment
4369 * target some other module, so avoid its connecting
4370 * to the target */
4371 return EXIT_SUCCESS;
4372 }
4373 }
4374 }
4375
Michal Vasko15b36692016-08-26 15:29:54 +02004376 if (!aug->child) {
4377 /* nothing to do */
4378 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004379 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004380 }
4381
Michal Vaskod58d5962016-03-02 14:29:41 +01004382 /* check for mandatory nodes - if the target node is in another module
4383 * the added nodes cannot be mandatory
4384 */
Michal Vasko15b36692016-08-26 15:29:54 +02004385 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004386 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004387 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004388 }
4389
Michal Vasko07e89ef2016-03-03 13:28:57 +01004390 /* check augment target type and then augment nodes type */
Michal Vaskodb017262017-01-24 13:10:04 +01004391 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
4392 LY_TREE_FOR(aug->child, sub) {
4393 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4394 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4395 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4396 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4397 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
4398 return -1;
4399 }
4400 }
4401 } else if (aug_target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004402 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004403 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004404 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004405 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004406 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004407 return -1;
4408 }
4409 }
Michal Vasko15b36692016-08-26 15:29:54 +02004410 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004411 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004412 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004413 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004414 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004415 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004416 return -1;
4417 }
4418 }
4419 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004420 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko51e5c582017-01-19 14:16:39 +01004421 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004422 return -1;
4423 }
4424
Radek Krejcic071c542016-01-27 14:57:51 +01004425 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004426 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004427 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004428 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004429 }
4430 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004431
Michal Vasko15b36692016-08-26 15:29:54 +02004432 /* finally reconnect augmenting data into the target - add them to the target child list,
4433 * by setting aug->target we know the augment is fully resolved now */
4434 aug->target = (struct lys_node *)aug_target;
4435 if (aug->target->child) {
4436 sub = aug->target->child->prev; /* remember current target's last node */
4437 sub->next = aug->child; /* connect augmenting data after target's last node */
4438 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4439 aug->child->prev = sub; /* finish connecting of both child lists */
4440 } else {
4441 aug->target->child = aug->child;
4442 }
4443
Michal Vasko9e635ac2016-10-17 11:44:09 +02004444 /* inherit config information from actual parent */
4445 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4446 clear_config = (parent) ? 1 : 0;
4447 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004448 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004449 return -1;
4450 }
4451 }
4452
Radek Krejci80056d52017-01-05 13:13:33 +01004453 /* inherit extensions if any */
4454 for (u = 0; u < aug->target->ext_size; u++) {
4455 ext = aug->target->ext[u]; /* shortcut */
4456 if (ext && ext->def->plugin && (ext->def->plugin->flags & LYEXT_OPT_INHERIT)) {
4457 unres_schema_add_node(mod, unres, &ext, UNRES_EXT_FINALIZE, NULL);
4458 }
4459 }
4460
Radek Krejci27fe55e2016-09-13 17:13:35 +02004461success:
4462 if (mod->implemented) {
4463 /* make target modules also implemented */
4464 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4465 if (lys_set_implemented(sub->module)) {
4466 return -1;
4467 }
4468 }
4469 }
4470
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004471 return EXIT_SUCCESS;
4472}
4473
Radek Krejcie534c132016-11-23 13:32:31 +01004474static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004475resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004476{
4477 enum LY_VLOG_ELEM vlog_type;
4478 void *vlog_node;
4479 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004480 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004481 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004482 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004483 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004484 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004485 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004486
4487 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004488 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004489 vlog_node = info->parent;
4490 vlog_type = LY_VLOG_LYS;
4491 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004492 case LYEXT_PAR_MODULE:
4493 case LYEXT_PAR_IMPORT:
4494 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004495 vlog_node = NULL;
4496 vlog_type = LY_VLOG_LYS;
4497 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004498 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004499 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004500 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004501 break;
4502 }
4503
4504 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004505 /* YIN */
4506
Radek Krejcie534c132016-11-23 13:32:31 +01004507 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004508 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004509 if (!mod) {
4510 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004511 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004512 }
4513
4514 /* find the extension definition */
4515 e = NULL;
4516 for (i = 0; i < mod->extensions_size; i++) {
4517 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4518 e = &mod->extensions[i];
4519 break;
4520 }
4521 }
4522 /* try submodules */
4523 for (j = 0; !e && j < mod->inc_size; j++) {
4524 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4525 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4526 e = &mod->inc[j].submodule->extensions[i];
4527 break;
4528 }
4529 }
4530 }
4531 if (!e) {
4532 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4533 return EXIT_FAILURE;
4534 }
4535
4536 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004537
Radek Krejci72b35992017-01-04 16:27:44 +01004538 if (e->plugin && e->plugin->check_position) {
4539 /* common part - we have plugin with position checking function, use it first */
4540 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4541 /* extension is not allowed here */
4542 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4543 return -1;
4544 }
4545 }
4546
Radek Krejci8d6b7422017-02-03 14:42:13 +01004547 /* extension type-specific part - allocation */
4548 if (e->plugin) {
4549 etype = e->plugin->type;
4550 } else {
4551 /* default type */
4552 etype = LYEXT_FLAG;
4553 }
4554 switch (etype) {
4555 case LYEXT_FLAG:
4556 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4557 break;
4558 case LYEXT_COMPLEX:
4559 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4560 break;
4561 case LYEXT_ERR:
4562 /* we never should be here */
4563 LOGINT;
4564 return -1;
4565 }
4566
4567 /* common part for all extension types */
4568 (*ext)->def = e;
4569 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004570 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004571 (*ext)->insubstmt = info->substmt;
4572 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004573 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004574
4575 if (!(e->flags & LYS_YINELEM) && e->argument) {
4576 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4577 if (!(*ext)->arg_value) {
4578 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4579 return -1;
4580 }
4581 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4582 }
4583
4584 /* extension type-specific part - parsing content */
4585 switch (etype) {
4586 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004587 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4588 if (!yin->ns) {
4589 /* garbage */
4590 lyxml_free(mod->ctx, yin);
4591 continue;
4592 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4593 /* standard YANG statements are not expected here */
4594 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4595 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004596 } else if (yin->ns == info->data.yin->ns &&
4597 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004598 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004599 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004600 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004601 return -1;
4602 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004603 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004604 yin->content = NULL;
4605 lyxml_free(mod->ctx, yin);
4606 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004607 /* extension instance */
4608 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4609 LYEXT_SUBSTMT_SELF, 0, unres)) {
4610 return -1;
4611 }
Radek Krejci72b35992017-01-04 16:27:44 +01004612
Radek Krejci72b35992017-01-04 16:27:44 +01004613 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004614 }
Radek Krejci72b35992017-01-04 16:27:44 +01004615 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004616 break;
4617 case LYEXT_COMPLEX:
Radek Krejcif95b6292017-02-13 15:57:37 +01004618 ((struct lys_ext_instance_complex*)(*ext))->nodetype = LYS_EXT;
Radek Krejci9722c6d2017-02-03 15:39:01 +01004619 ((struct lys_ext_instance_complex*)(*ext))->module = info->mod;
Radek Krejcifebdad72017-02-06 11:35:51 +01004620 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004621 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4622 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004623 return -1;
4624 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004625 break;
4626 default:
4627 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004628 }
Radek Krejci72b35992017-01-04 16:27:44 +01004629
4630 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4631
Radek Krejcie534c132016-11-23 13:32:31 +01004632 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004633 /* YANG */
4634
PavolVicanc1807262017-01-31 18:00:27 +01004635 ext_prefix = (char *)(*ext)->def;
4636 tmp = strchr(ext_prefix, ':');
4637 if (!tmp) {
4638 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004639 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004640 }
4641 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004642
PavolVicanc1807262017-01-31 18:00:27 +01004643 /* get the module where the extension is supposed to be defined */
4644 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4645 if (!mod) {
4646 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4647 return EXIT_FAILURE;
4648 }
4649
4650 /* find the extension definition */
4651 e = NULL;
4652 for (i = 0; i < mod->extensions_size; i++) {
4653 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4654 e = &mod->extensions[i];
4655 break;
4656 }
4657 }
4658 /* try submodules */
4659 for (j = 0; !e && j < mod->inc_size; j++) {
4660 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4661 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4662 e = &mod->inc[j].submodule->extensions[i];
4663 break;
4664 }
4665 }
4666 }
4667 if (!e) {
4668 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4669 return EXIT_FAILURE;
4670 }
4671
4672 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4673
4674 if (e->plugin && e->plugin->check_position) {
4675 /* common part - we have plugin with position checking function, use it first */
4676 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4677 /* extension is not allowed here */
4678 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004679 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004680 }
4681 }
4682
PavolVican22e88682017-02-14 22:38:18 +01004683 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004684 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004685 (*ext)->def = e;
4686 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004687 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004688
PavolVicanb0d84102017-02-15 16:32:42 +01004689 if (e->argument && !(*ext)->arg_value) {
4690 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4691 goto error;
4692 }
4693
PavolVican22e88682017-02-14 22:38:18 +01004694 /* extension type-specific part */
4695 if (e->plugin) {
4696 etype = e->plugin->type;
4697 } else {
4698 /* default type */
4699 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004700 }
PavolVican22e88682017-02-14 22:38:18 +01004701 switch (etype) {
4702 case LYEXT_FLAG:
4703 /* nothing change */
4704 break;
4705 case LYEXT_COMPLEX:
4706 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4707 if (!tmp_ext) {
4708 LOGMEM;
4709 goto error;
4710 }
4711 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4712 (*ext) = tmp_ext;
4713 ((struct lys_ext_instance_complex*)(*ext))->module = info->mod;
4714 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
4715 break;
4716 case LYEXT_ERR:
4717 /* we never should be here */
4718 LOGINT;
4719 goto error;
4720 }
4721
4722 if (info->data.yang) {
4723 *tmp = ':';
4724 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang, ext_prefix, (struct lys_ext_instance_complex*)(*ext))) {
4725 goto error;
4726 }
4727 }
4728 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4729 goto error;
4730 }
4731 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004732 }
4733
4734 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004735error:
4736 free(ext_prefix);
4737 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004738}
4739
Michal Vasko730dfdf2015-08-11 14:48:05 +02004740/**
Pavol Vican855ca622016-09-05 13:07:54 +02004741 * @brief Resolve (find) choice default case. Does not log.
4742 *
4743 * @param[in] choic Choice to use.
4744 * @param[in] dflt Name of the default case.
4745 *
4746 * @return Pointer to the default node or NULL.
4747 */
4748static struct lys_node *
4749resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4750{
4751 struct lys_node *child, *ret;
4752
4753 LY_TREE_FOR(choic->child, child) {
4754 if (child->nodetype == LYS_USES) {
4755 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4756 if (ret) {
4757 return ret;
4758 }
4759 }
4760
4761 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004762 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004763 return child;
4764 }
4765 }
4766
4767 return NULL;
4768}
4769
4770/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004771 * @brief Resolve uses, apply augments, refines. Logs directly.
4772 *
Michal Vaskobb211122015-08-19 14:03:11 +02004773 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004774 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004775 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004776 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004777 */
Michal Vasko184521f2015-09-24 13:14:26 +02004778static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004779resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004780{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004781 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004782 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004783 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004784 struct lys_node_leaflist *llist;
4785 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004786 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004787 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004788 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004789 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004790 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004791 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004792
Michal Vasko71e1aa82015-08-12 12:17:51 +02004793 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004794
4795 /* HACK just check that the grouping is resolved
4796 * - the higher byte in flags is always empty in grouping (no flags there apply to the groupings)
4797 * so we use it to count unresolved uses inside the grouping */
4798#if __BYTE_ORDER == __LITTLE_ENDIAN
4799 assert(!((uint8_t*)&uses->grp->flags)[1]);
4800#else
4801 assert(!((uint8_t*)&uses->grp->flags)[0]);
4802#endif
Michal Vasko71e1aa82015-08-12 12:17:51 +02004803
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004804 if (!uses->grp->child) {
4805 /* grouping without children, warning was already displayed */
4806 return EXIT_SUCCESS;
4807 }
4808
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004809 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004810 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004811 if (node_aux->nodetype & LYS_GROUPING) {
4812 /* do not instantiate groupings from groupings */
4813 continue;
4814 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004815 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004816 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004817 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004818 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004819 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004820 }
Pavol Vican55abd332016-07-12 15:54:49 +02004821 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004822 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 +02004823 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004824 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004825 }
4826 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004827 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004828
Michal Vaskodef0db12015-10-07 13:22:48 +02004829 /* we managed to copy the grouping, the rest must be possible to resolve */
4830
Pavol Vican855ca622016-09-05 13:07:54 +02004831 if (uses->refine_size) {
4832 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4833 if (!refine_nodes) {
4834 LOGMEM;
4835 goto fail;
4836 }
4837 }
4838
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004839 /* apply refines */
4840 for (i = 0; i < uses->refine_size; i++) {
4841 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004842 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4843 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004844 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004845 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004846 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004847 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004848 }
4849
Radek Krejci1d82ef62015-08-07 14:44:40 +02004850 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004851 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004852 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004853 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004854 }
Pavol Vican855ca622016-09-05 13:07:54 +02004855 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004856
4857 /* description on any nodetype */
4858 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004859 lydict_remove(ctx, node->dsc);
4860 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004861 }
4862
4863 /* reference on any nodetype */
4864 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004865 lydict_remove(ctx, node->ref);
4866 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004867 }
4868
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004869 /* config on any nodetype,
4870 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4871 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004872 node->flags &= ~LYS_CONFIG_MASK;
4873 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004874 }
4875
4876 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004877 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004878 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004879 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004880 leaf = (struct lys_node_leaf *)node;
4881
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004882 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004883 lydict_remove(ctx, leaf->dflt);
4884 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4885
4886 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004887 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4888 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004889 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004890 }
Radek Krejci200bf712016-08-16 17:11:04 +02004891 } else if (node->nodetype == LYS_LEAFLIST) {
4892 /* leaf-list */
4893 llist = (struct lys_node_leaflist *)node;
4894
4895 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004896 for (j = 0; j < llist->dflt_size; j++) {
4897 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004898 }
4899 free(llist->dflt);
4900
4901 /* copy the default set from refine */
4902 llist->dflt_size = rfn->dflt_size;
4903 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
Radek Krejci542ab142017-01-23 15:57:08 +01004904 for (j = 0; j < llist->dflt_size; j++) {
4905 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004906 }
4907
4908 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004909 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004910 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004911 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004912 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004913 }
4914 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004915 }
4916 }
4917
4918 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004919 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004920 /* remove current value */
4921 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004922
Radek Krejcibf285832017-01-26 16:05:41 +01004923 /* set new value */
4924 node->flags |= (rfn->flags & LYS_MAND_MASK);
4925
Pavol Vican855ca622016-09-05 13:07:54 +02004926 if (rfn->flags & LYS_MAND_TRUE) {
4927 /* check if node has default value */
4928 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4929 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4930 goto fail;
4931 }
4932 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4933 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4934 goto fail;
4935 }
4936 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004937 }
4938
4939 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004940 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4941 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4942 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004943 }
4944
4945 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004946 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004947 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004948 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004949 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004950 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004951 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004952 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004953 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004954 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004955 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004956 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004957 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004958 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004959 }
4960 }
4961
4962 /* must in leaf, leaf-list, list, container or anyxml */
4963 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004964 switch (node->nodetype) {
4965 case LYS_LEAF:
4966 old_size = &((struct lys_node_leaf *)node)->must_size;
4967 old_must = &((struct lys_node_leaf *)node)->must;
4968 break;
4969 case LYS_LEAFLIST:
4970 old_size = &((struct lys_node_leaflist *)node)->must_size;
4971 old_must = &((struct lys_node_leaflist *)node)->must;
4972 break;
4973 case LYS_LIST:
4974 old_size = &((struct lys_node_list *)node)->must_size;
4975 old_must = &((struct lys_node_list *)node)->must;
4976 break;
4977 case LYS_CONTAINER:
4978 old_size = &((struct lys_node_container *)node)->must_size;
4979 old_must = &((struct lys_node_container *)node)->must;
4980 break;
4981 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004982 case LYS_ANYDATA:
4983 old_size = &((struct lys_node_anydata *)node)->must_size;
4984 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004985 break;
4986 default:
4987 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004988 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004989 }
4990
4991 size = *old_size + rfn->must_size;
4992 must = realloc(*old_must, size * sizeof *rfn->must);
4993 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004994 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004995 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004996 }
Pavol Vican855ca622016-09-05 13:07:54 +02004997 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004998 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004999 lys_ext_dup(rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejcifdc0d702017-01-23 15:58:38 +01005000 &must[j].ext, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02005001 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5002 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5003 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5004 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5005 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005006 }
5007
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005008 *old_must = must;
5009 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02005010
5011 /* check XPath dependencies again */
5012 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5013 goto fail;
5014 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005015 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02005016
5017 /* if-feature in leaf, leaf-list, list, container or anyxml */
5018 if (rfn->iffeature_size) {
5019 old_size = &node->iffeature_size;
5020 old_iff = &node->iffeature;
5021
5022 size = *old_size + rfn->iffeature_size;
5023 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
5024 if (!iff) {
5025 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005026 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02005027 }
Pavol Vican855ca622016-09-05 13:07:54 +02005028 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5029 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005030 if (usize1) {
5031 /* there is something to duplicate */
5032 /* duplicate compiled expression */
5033 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
5034 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02005035 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005036
5037 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005038 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
5039 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005040 }
5041 }
5042
5043 *old_iff = iff;
5044 *old_size = size;
5045 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005046 }
5047
5048 /* apply augments */
5049 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01005050 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005051 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005052 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005053 }
5054 }
5055
Pavol Vican855ca622016-09-05 13:07:54 +02005056 /* check refines */
5057 for (i = 0; i < uses->refine_size; i++) {
5058 node = refine_nodes[i];
5059 rfn = &uses->refine[i];
5060
5061 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005062 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005063 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005064 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005065 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5066 (rfn->flags & LYS_CONFIG_W)) {
5067 /* setting config true under config false is prohibited */
5068 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01005069 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005070 "changing config from 'false' to 'true' is prohibited while "
5071 "the target's parent is still config 'false'.");
5072 goto fail;
5073 }
5074
5075 /* inherit config change to the target children */
5076 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5077 if (rfn->flags & LYS_CONFIG_W) {
5078 if (iter->flags & LYS_CONFIG_SET) {
5079 /* config is set explicitely, go to next sibling */
5080 next = NULL;
5081 goto nextsibling;
5082 }
5083 } else { /* LYS_CONFIG_R */
5084 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5085 /* error - we would have config data under status data */
5086 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01005087 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005088 "changing config from 'true' to 'false' is prohibited while the target "
5089 "has still a children with explicit config 'true'.");
5090 goto fail;
5091 }
5092 }
5093 /* change config */
5094 iter->flags &= ~LYS_CONFIG_MASK;
5095 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5096
5097 /* select next iter - modified LY_TREE_DFS_END */
5098 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5099 next = NULL;
5100 } else {
5101 next = iter->child;
5102 }
5103nextsibling:
5104 if (!next) {
5105 /* try siblings */
5106 next = iter->next;
5107 }
5108 while (!next) {
5109 /* parent is already processed, go to its sibling */
5110 iter = lys_parent(iter);
5111
5112 /* no siblings, go back through parents */
5113 if (iter == node) {
5114 /* we are done, no next element to process */
5115 break;
5116 }
5117 next = iter->next;
5118 }
5119 }
5120 }
5121
5122 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005123 if (rfn->dflt_size) {
5124 if (node->nodetype == LYS_CHOICE) {
5125 /* choice */
5126 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5127 rfn->dflt[0]);
5128 if (!((struct lys_node_choice *)node)->dflt) {
5129 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
5130 goto fail;
5131 }
5132 if (lyp_check_mandatory_choice(node)) {
5133 goto fail;
5134 }
Pavol Vican855ca622016-09-05 13:07:54 +02005135 }
5136 }
5137
5138 /* min/max-elements on list or leaf-list */
5139 if (node->nodetype == LYS_LIST) {
5140 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
5141 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5142 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5143 goto fail;
5144 }
5145 } else if (node->nodetype == LYS_LEAFLIST) {
5146 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
5147 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5148 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5149 goto fail;
5150 }
5151 }
5152
5153 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005154 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005155 if (node->nodetype == LYS_LEAFLIST) {
5156 llist = (struct lys_node_leaflist *)node;
5157 if (llist->dflt_size && llist->min) {
5158 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
5159 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
5160 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5161 goto fail;
5162 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005163 } else if (node->nodetype == LYS_LEAF) {
5164 leaf = (struct lys_node_leaf *)node;
5165 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
5166 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
5167 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
5168 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5169 goto fail;
5170 }
Pavol Vican855ca622016-09-05 13:07:54 +02005171 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005172
Pavol Vican855ca622016-09-05 13:07:54 +02005173 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005174 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005175 for (parent = node->parent;
5176 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5177 parent = parent->parent) {
5178 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5179 /* stop also on presence containers */
5180 break;
5181 }
5182 }
5183 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5184 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5185 if (lyp_check_mandatory_choice(parent)) {
5186 goto fail;
5187 }
5188 }
5189 }
5190 }
5191 free(refine_nodes);
5192
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005193 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005194
5195fail:
5196 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5197 lys_node_free(iter, NULL, 0);
5198 }
Pavol Vican855ca622016-09-05 13:07:54 +02005199 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005200 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005201}
5202
Radek Krejci83a4bac2017-02-07 15:53:04 +01005203void
5204resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005205{
5206 int i;
5207
5208 assert(der && base);
5209
Radek Krejci018f1f52016-08-03 16:01:20 +02005210 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005211 /* create a set for backlinks if it does not exist */
5212 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005213 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005214 /* store backlink */
5215 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005216
Radek Krejci85a54be2016-10-20 12:39:56 +02005217 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005218 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005219 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005220 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005221}
5222
Michal Vasko730dfdf2015-08-11 14:48:05 +02005223/**
5224 * @brief Resolve base identity recursively. Does not log.
5225 *
5226 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005227 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005228 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005229 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005230 *
Radek Krejci219fa612016-08-15 10:36:51 +02005231 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005232 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005233static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005234resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005235 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005236{
Michal Vaskof02e3742015-08-05 16:27:02 +02005237 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005238 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005239
Radek Krejcicf509982015-12-15 09:22:44 +01005240 assert(ret);
5241
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005242 /* search module */
5243 for (i = 0; i < module->ident_size; i++) {
5244 if (!strcmp(basename, module->ident[i].name)) {
5245
5246 if (!ident) {
5247 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005248 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005249 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005250 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005251 }
5252
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005253 base = &module->ident[i];
5254 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005255 }
5256 }
5257
5258 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005259 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5260 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5261 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005262
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005263 if (!ident) {
5264 *ret = &module->inc[j].submodule->ident[i];
5265 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005266 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005267
5268 base = &module->inc[j].submodule->ident[i];
5269 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005270 }
5271 }
5272 }
5273
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005274matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005275 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005276 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005277 /* is it already completely resolved? */
5278 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005279 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005280 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5281
5282 /* simple check for circular reference,
5283 * the complete check is done as a side effect of using only completely
5284 * resolved identities (previous check of unres content) */
5285 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5286 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5287 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005288 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005289 }
5290
Radek Krejci06f64ed2016-08-15 11:07:44 +02005291 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005292 }
5293 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005294
Radek Krejcibabbff82016-02-19 13:31:37 +01005295 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005296 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005297 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005298 }
5299
Radek Krejci219fa612016-08-15 10:36:51 +02005300 /* base not found (maybe a forward reference) */
5301 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005302}
5303
Michal Vasko730dfdf2015-08-11 14:48:05 +02005304/**
5305 * @brief Resolve base identity. Logs directly.
5306 *
5307 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005308 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005309 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005310 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005311 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005312 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005313 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005314 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005315static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005316resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005317 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005318{
5319 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005320 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005321 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005322 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005323 struct lys_module *mod;
5324
5325 assert((ident && !type) || (!ident && type));
5326
5327 if (!type) {
5328 /* have ident to resolve */
5329 ret = &target;
5330 flags = ident->flags;
5331 mod = ident->module;
5332 } else {
5333 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005334 ++type->info.ident.count;
5335 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5336 if (!type->info.ident.ref) {
5337 LOGMEM;
5338 return -1;
5339 }
5340
5341 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005342 flags = type->parent->flags;
5343 mod = type->parent->module;
5344 }
Michal Vaskof2006002016-04-21 16:28:15 +02005345 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005346
5347 /* search for the base identity */
5348 name = strchr(basename, ':');
5349 if (name) {
5350 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005351 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005352 name++;
5353
Michal Vasko2d851a92015-10-20 16:16:36 +02005354 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005355 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005356 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005357 }
5358 } else {
5359 name = basename;
5360 }
5361
Radek Krejcic071c542016-01-27 14:57:51 +01005362 /* get module where to search */
5363 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5364 if (!module) {
5365 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005366 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005367 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005368 }
5369
Radek Krejcic071c542016-01-27 14:57:51 +01005370 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005371 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5372 if (!rc) {
5373 assert(*ret);
5374
5375 /* check status */
5376 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5377 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5378 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005379 } else if (ident) {
5380 ident->base[ident->base_size++] = *ret;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005381
Radek Krejci83a4bac2017-02-07 15:53:04 +01005382 /* maintain backlinks to the derived identities */
5383 resolve_identity_backlink_update(ident, *ret);
Radek Krejci219fa612016-08-15 10:36:51 +02005384 }
5385 } else if (rc == EXIT_FAILURE) {
5386 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005387 if (type) {
5388 --type->info.ident.count;
5389 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005390 }
5391
Radek Krejci219fa612016-08-15 10:36:51 +02005392 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005393}
5394
Michal Vasko730dfdf2015-08-11 14:48:05 +02005395/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005396 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005397 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005398 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005399 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005400 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005401 *
5402 * @return Pointer to the identity resolvent, NULL on error.
5403 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005404struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005405resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005406{
Radek Krejci639491e2016-12-05 13:30:42 +01005407 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005408 int mod_name_len, rc, i;
5409 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005410 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005411
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005412 assert(type && ident_name && node);
5413
Michal Vaskof2d43962016-09-02 11:10:16 +02005414 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005415 return NULL;
5416 }
5417
Michal Vaskoc633ca02015-08-21 14:03:51 +02005418 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005419 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005420 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005421 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005422 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005423 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005424 return NULL;
5425 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005426 if (!mod_name) {
5427 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005428 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005429 mod_name_len = strlen(mod_name);
5430 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005431
Michal Vaskof2d43962016-09-02 11:10:16 +02005432 /* go through all the bases in all the derived types */
5433 while (type->der) {
5434 for (i = 0; i < type->info.ident.count; ++i) {
5435 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005436 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005437 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005438 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005439 goto match;
5440 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005441
Radek Krejci85a54be2016-10-20 12:39:56 +02005442 if (cur->der) {
5443 /* there are also some derived identities */
5444 for (u = 0; u < cur->der->number; u++) {
5445 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005446 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005447 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005448 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005449 /* we have match */
5450 cur = der;
5451 goto match;
5452 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005453 }
5454 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005455 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005456 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005457 }
5458
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005459 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005460 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005461
5462match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005463 for (i = 0; i < cur->iffeature_size; i++) {
5464 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005465 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005466 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 +02005467 return NULL;
5468 }
5469 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005470 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005471}
5472
Michal Vasko730dfdf2015-08-11 14:48:05 +02005473/**
Michal Vaskobb211122015-08-19 14:03:11 +02005474 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005475 *
Michal Vaskobb211122015-08-19 14:03:11 +02005476 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005477 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005478 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005479 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005480 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005481static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005482resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005483{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005484 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005485 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005486
Radek Krejci6ff885d2017-01-03 14:06:22 +01005487 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
5488 * in some uses. When we see such a uses, the grouping's higher byte of the flags member (not used in
5489 * grouping) is used to store number of so far unresolved uses. The grouping cannot be used unless this
5490 * counter is decreased back to 0. To remember that the uses already increased grouping's counter, the
Radek Krejci010e54b2016-03-15 09:40:34 +01005491 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005492 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 +02005493
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005494 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005495 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5496 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005497 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005498 return -1;
5499 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005500 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005501 return -1;
5502 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005503 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005504 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5505 * (and smaller flags - it uses only a limited set of flags)
5506 */
Radek Krejci6ff885d2017-01-03 14:06:22 +01005507#if __BYTE_ORDER == __LITTLE_ENDIAN
5508 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
5509#else
5510 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
5511#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005512 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005513 }
Michal Vasko92981a62016-10-14 10:25:16 +02005514 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005515 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005516 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005517 }
5518
Radek Krejci6ff885d2017-01-03 14:06:22 +01005519#if __BYTE_ORDER == __LITTLE_ENDIAN
5520 if (((uint8_t*)&uses->grp->flags)[1]) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005521 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01005522 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
5523#else
5524 if (((uint8_t*)&uses->grp->flags)[0]) {
5525 if (par_grp && !(uses->flags & LYS_USESGRP)) {
5526 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
5527#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005528 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005529 } else {
5530 /* instantiate grouping only when it is completely resolved */
5531 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005532 }
Michal Vasko92981a62016-10-14 10:25:16 +02005533 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005534 return EXIT_FAILURE;
5535 }
5536
Radek Krejci48464ed2016-03-17 15:44:09 +01005537 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005538 if (!rc) {
5539 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005540 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01005541#if __BYTE_ORDER == __LITTLE_ENDIAN
5542 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]) {;
5543#else
5544 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]) {;
5545#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005546 LOGINT;
5547 return -1;
5548 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01005549#if __BYTE_ORDER == __LITTLE_ENDIAN
5550 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]--;
5551#else
5552 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]--;
5553#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005554 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005555 }
Radek Krejcicf509982015-12-15 09:22:44 +01005556
5557 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005558 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005559 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005560 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005561 return -1;
5562 }
5563
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005564 return EXIT_SUCCESS;
5565 }
5566
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005567 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005568}
5569
Michal Vasko730dfdf2015-08-11 14:48:05 +02005570/**
Michal Vasko9957e592015-08-17 15:04:09 +02005571 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005572 *
Michal Vaskobb211122015-08-19 14:03:11 +02005573 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005574 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005575 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005576 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005577 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005578static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005579resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005580{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005581 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005582 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005583
5584 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005585 if (!list->child) {
5586 /* no child, possible forward reference */
5587 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5588 return EXIT_FAILURE;
5589 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005590 /* get the key name */
5591 if ((value = strpbrk(keys_str, " \t\n"))) {
5592 len = value - keys_str;
5593 while (isspace(value[0])) {
5594 value++;
5595 }
5596 } else {
5597 len = strlen(keys_str);
5598 }
5599
Michal Vasko0f99d3e2017-01-10 10:50:40 +01005600 rc = lys_get_data_sibling(lys_node_module((struct lys_node *)list), list->child, keys_str, len, LYS_LEAF,
5601 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005602 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005603 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5604 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005605 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005606
Radek Krejci48464ed2016-03-17 15:44:09 +01005607 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005608 /* check_key logs */
5609 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005610 }
5611
Radek Krejcicf509982015-12-15 09:22:44 +01005612 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005613 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005614 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5615 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005616 return -1;
5617 }
5618
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005619 /* prepare for next iteration */
5620 while (value && isspace(value[0])) {
5621 value++;
5622 }
5623 keys_str = value;
5624 }
5625
Michal Vaskof02e3742015-08-05 16:27:02 +02005626 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005627}
5628
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005629/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005630 * @brief Resolve (check) all must conditions of \p node.
5631 * Logs directly.
5632 *
5633 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005634 * @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 +02005635 *
5636 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5637 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005638static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005639resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005640{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005641 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005642 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005643 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005644 struct lys_restr *must;
5645 struct lyxp_set set;
5646
5647 assert(node);
5648 memset(&set, 0, sizeof set);
5649
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005650 if (inout_parent) {
5651 for (schema = lys_parent(node->schema);
5652 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5653 schema = lys_parent(schema));
5654 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5655 LOGINT;
5656 return -1;
5657 }
5658 must_size = ((struct lys_node_inout *)schema)->must_size;
5659 must = ((struct lys_node_inout *)schema)->must;
5660
Michal Vasko3cfa3182017-01-17 10:00:58 +01005661 node_flags = schema->flags;
5662
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005663 /* context node is the RPC/action */
5664 node = node->parent;
5665 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5666 LOGINT;
5667 return -1;
5668 }
5669 } else {
5670 switch (node->schema->nodetype) {
5671 case LYS_CONTAINER:
5672 must_size = ((struct lys_node_container *)node->schema)->must_size;
5673 must = ((struct lys_node_container *)node->schema)->must;
5674 break;
5675 case LYS_LEAF:
5676 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5677 must = ((struct lys_node_leaf *)node->schema)->must;
5678 break;
5679 case LYS_LEAFLIST:
5680 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5681 must = ((struct lys_node_leaflist *)node->schema)->must;
5682 break;
5683 case LYS_LIST:
5684 must_size = ((struct lys_node_list *)node->schema)->must_size;
5685 must = ((struct lys_node_list *)node->schema)->must;
5686 break;
5687 case LYS_ANYXML:
5688 case LYS_ANYDATA:
5689 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5690 must = ((struct lys_node_anydata *)node->schema)->must;
5691 break;
5692 case LYS_NOTIF:
5693 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5694 must = ((struct lys_node_notif *)node->schema)->must;
5695 break;
5696 default:
5697 must_size = 0;
5698 break;
5699 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005700
5701 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005702 }
5703
5704 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005705 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005706 return -1;
5707 }
5708
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005709 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005710
Michal Vasko8146d4c2016-05-09 15:50:29 +02005711 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005712 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005713 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5714 } else {
5715 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5716 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005717 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005718 }
5719 if (must[i].eapptag) {
5720 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5721 }
5722 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005723 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005724 }
5725 }
5726
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005727 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005728}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005729
Michal Vaskobf19d252015-10-08 15:39:17 +02005730/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005731 * @brief Resolve (find) when condition schema context node. Does not log.
5732 *
5733 * @param[in] schema Schema node with the when condition.
5734 * @param[out] ctx_snode When schema context node.
5735 * @param[out] ctx_snode_type Schema context node type.
5736 */
5737void
5738resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5739{
5740 const struct lys_node *sparent;
5741
5742 /* find a not schema-only node */
5743 *ctx_snode_type = LYXP_NODE_ELEM;
5744 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5745 if (schema->nodetype == LYS_AUGMENT) {
5746 sparent = ((struct lys_node_augment *)schema)->target;
5747 } else {
5748 sparent = schema->parent;
5749 }
5750 if (!sparent) {
5751 /* context node is the document root (fake root in our case) */
5752 if (schema->flags & LYS_CONFIG_W) {
5753 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5754 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005755 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005756 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005757 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005758 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005759 break;
5760 }
5761 schema = sparent;
5762 }
5763
5764 *ctx_snode = (struct lys_node *)schema;
5765}
5766
5767/**
Michal Vaskocf024702015-10-08 15:01:42 +02005768 * @brief Resolve (find) when condition context node. Does not log.
5769 *
5770 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005771 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005772 * @param[out] ctx_node Context node.
5773 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005774 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005775 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005776 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005777static int
5778resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5779 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005780{
Michal Vaskocf024702015-10-08 15:01:42 +02005781 struct lyd_node *parent;
5782 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005783 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005784 uint16_t i, data_depth, schema_depth;
5785
Michal Vasko508a50d2016-09-07 14:50:33 +02005786 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005787
Michal Vaskofe989752016-09-08 08:47:26 +02005788 if (node_type == LYXP_NODE_ELEM) {
5789 /* standard element context node */
5790 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5791 for (sparent = schema, schema_depth = 0;
5792 sparent;
5793 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5794 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5795 ++schema_depth;
5796 }
Michal Vaskocf024702015-10-08 15:01:42 +02005797 }
Michal Vaskofe989752016-09-08 08:47:26 +02005798 if (data_depth < schema_depth) {
5799 return -1;
5800 }
Michal Vaskocf024702015-10-08 15:01:42 +02005801
Michal Vasko956e8542016-08-26 09:43:35 +02005802 /* find the corresponding data node */
5803 for (i = 0; i < data_depth - schema_depth; ++i) {
5804 node = node->parent;
5805 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005806 if (node->schema != schema) {
5807 return -1;
5808 }
Michal Vaskofe989752016-09-08 08:47:26 +02005809 } else {
5810 /* root context node */
5811 while (node->parent) {
5812 node = node->parent;
5813 }
5814 while (node->prev->next) {
5815 node = node->prev;
5816 }
Michal Vaskocf024702015-10-08 15:01:42 +02005817 }
5818
Michal Vaskoa59495d2016-08-22 09:18:58 +02005819 *ctx_node = node;
5820 *ctx_node_type = node_type;
5821 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005822}
5823
Michal Vasko76c3bd32016-08-24 16:02:52 +02005824/**
5825 * @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 +01005826 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005827 *
5828 * @param[in] snode Schema node, whose children instances need to be unlinked.
5829 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5830 * it is moved to point to another sibling still in the original tree.
5831 * @param[in,out] ctx_node When context node, adjusted if needed.
5832 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5833 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5834 * Ordering may change, but there will be no semantic change.
5835 *
5836 * @return EXIT_SUCCESS on success, -1 on error.
5837 */
5838static int
5839resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5840 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5841{
5842 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005843 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005844
5845 switch (snode->nodetype) {
5846 case LYS_AUGMENT:
5847 case LYS_USES:
5848 case LYS_CHOICE:
5849 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005850 slast = NULL;
5851 while ((slast = lys_getnext(slast, snode, NULL, 0))) {
5852 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5853 continue;
5854 }
5855
5856 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005857 return -1;
5858 }
5859 }
5860 break;
5861 case LYS_CONTAINER:
5862 case LYS_LIST:
5863 case LYS_LEAF:
5864 case LYS_LEAFLIST:
5865 case LYS_ANYXML:
5866 case LYS_ANYDATA:
5867 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5868 if (elem->schema == snode) {
5869
5870 if (elem == *ctx_node) {
5871 /* We are going to unlink our context node! This normally cannot happen,
5872 * but we use normal top-level data nodes for faking a document root node,
5873 * so if this is the context node, we just use the next top-level node.
5874 * Additionally, it can even happen that there are no top-level data nodes left,
5875 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5876 * lyxp_eval() can handle this special situation.
5877 */
5878 if (ctx_node_type == LYXP_NODE_ELEM) {
5879 LOGINT;
5880 return -1;
5881 }
5882
5883 if (elem->prev == elem) {
5884 /* unlinking last top-level element, use an empty data tree */
5885 *ctx_node = NULL;
5886 } else {
5887 /* in this case just use the previous/last top-level data node */
5888 *ctx_node = elem->prev;
5889 }
5890 } else if (elem == *node) {
5891 /* We are going to unlink the currently processed node. This does not matter that
5892 * much, but we would lose access to the original data tree, so just move our
5893 * pointer somewhere still inside it.
5894 */
5895 if ((*node)->prev != *node) {
5896 *node = (*node)->prev;
5897 } else {
5898 /* the processed node with sibings were all unlinked, oh well */
5899 *node = NULL;
5900 }
5901 }
5902
5903 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005904 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005905 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005906 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005907 LOGINT;
5908 return -1;
5909 }
5910 } else {
5911 *unlinked_nodes = elem;
5912 }
5913
5914 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5915 /* there can be only one instance */
5916 break;
5917 }
5918 }
5919 }
5920 break;
5921 default:
5922 LOGINT;
5923 return -1;
5924 }
5925
5926 return EXIT_SUCCESS;
5927}
5928
5929/**
5930 * @brief Relink the unlinked nodes back.
5931 *
5932 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5933 * we simply need a sibling from the original data tree.
5934 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5935 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5936 * or the sibling of \p unlinked_nodes.
5937 *
5938 * @return EXIT_SUCCESS on success, -1 on error.
5939 */
5940static int
5941resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5942{
5943 struct lyd_node *elem;
5944
5945 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005946 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005947 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005948 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005949 return -1;
5950 }
5951 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005952 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005953 return -1;
5954 }
5955 }
5956 }
5957
5958 return EXIT_SUCCESS;
5959}
5960
Radek Krejci03b71f72016-03-16 11:10:09 +01005961int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005962resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005963{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005964 int ret = 0;
5965 uint8_t must_size;
5966 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005967
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005968 assert(node);
5969
5970 schema = node->schema;
5971
5972 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005973 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005974 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005975 must_size = ((struct lys_node_container *)schema)->must_size;
5976 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005977 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005978 must_size = ((struct lys_node_leaf *)schema)->must_size;
5979 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005980 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005981 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5982 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005983 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005984 must_size = ((struct lys_node_list *)schema)->must_size;
5985 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005986 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005987 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005988 must_size = ((struct lys_node_anydata *)schema)->must_size;
5989 break;
5990 case LYS_NOTIF:
5991 must_size = ((struct lys_node_notif *)schema)->must_size;
5992 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005993 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005994 must_size = 0;
5995 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005996 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005997
5998 if (must_size) {
5999 ++ret;
6000 }
6001
6002 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6003 if (!node->prev->next) {
6004 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6005 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6006 ret += 0x2;
6007 }
6008 }
6009
6010 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006011}
6012
6013int
Radek Krejci46165822016-08-26 14:06:27 +02006014resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006015{
Radek Krejci46165822016-08-26 14:06:27 +02006016 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006017
Radek Krejci46165822016-08-26 14:06:27 +02006018 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006019
Radek Krejci46165822016-08-26 14:06:27 +02006020 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006021 return 1;
6022 }
6023
Radek Krejci46165822016-08-26 14:06:27 +02006024 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006025 goto check_augment;
6026
Radek Krejci46165822016-08-26 14:06:27 +02006027 while (parent) {
6028 /* stop conditions */
6029 if (!mode) {
6030 /* stop on node that can be instantiated in data tree */
6031 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6032 break;
6033 }
6034 } else {
6035 /* stop on the specified node */
6036 if (parent == stop) {
6037 break;
6038 }
6039 }
6040
6041 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006042 return 1;
6043 }
6044check_augment:
6045
6046 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006047 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006048 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006049 }
6050 parent = lys_parent(parent);
6051 }
6052
6053 return 0;
6054}
6055
Michal Vaskocf024702015-10-08 15:01:42 +02006056/**
6057 * @brief Resolve (check) all when conditions relevant for \p node.
6058 * Logs directly.
6059 *
6060 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02006061 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006062 * @return
6063 * -1 - error, ly_errno is set
6064 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02006065 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01006066 * 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 +02006067 */
Radek Krejci46165822016-08-26 14:06:27 +02006068int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006069resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02006070{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006071 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006072 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006073 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006074 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02006075 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006076
6077 assert(node);
6078 memset(&set, 0, sizeof set);
6079
6080 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006081 /* make the node dummy for the evaluation */
6082 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006083 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6084 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006085 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006086 if (rc) {
6087 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006088 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006089 }
Radek Krejci51093642016-03-29 10:14:59 +02006090 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006091 }
6092
Radek Krejci03b71f72016-03-16 11:10:09 +01006093 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006094 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006095 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006096 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006097 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006098 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6099 ((struct lys_node_container *)node->schema)->when->cond);
6100 } else {
6101 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
6102 goto cleanup;
6103 }
Michal Vaskocf024702015-10-08 15:01:42 +02006104 }
Radek Krejci51093642016-03-29 10:14:59 +02006105
6106 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006107 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006108 }
6109
Michal Vasko90fc2a32016-08-24 15:58:58 +02006110 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006111 goto check_augment;
6112
6113 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006114 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6115 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006116 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006117 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006118 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006119 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006120 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006121 }
6122 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006123
6124 unlinked_nodes = NULL;
6125 /* we do not want our node pointer to change */
6126 tmp_node = node;
6127 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6128 if (rc) {
6129 goto cleanup;
6130 }
6131
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006132 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6133 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006134
6135 if (unlinked_nodes && ctx_node) {
6136 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6137 rc = -1;
6138 goto cleanup;
6139 }
6140 }
6141
Radek Krejci03b71f72016-03-16 11:10:09 +01006142 if (rc) {
6143 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006144 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006145 }
Radek Krejci51093642016-03-29 10:14:59 +02006146 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006147 }
6148
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006149 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006150 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006151 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006152 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006153 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6154 ((struct lys_node_uses *)sparent)->when->cond);
6155 } else {
6156 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6157 goto cleanup;
6158 }
Michal Vaskocf024702015-10-08 15:01:42 +02006159 }
Radek Krejci51093642016-03-29 10:14:59 +02006160
6161 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006162 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006163 }
6164
6165check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006166 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006167 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006168 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006169 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006170 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006171 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006172 }
6173 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006174
6175 unlinked_nodes = NULL;
6176 tmp_node = node;
6177 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6178 if (rc) {
6179 goto cleanup;
6180 }
6181
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006182 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6183 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006184
6185 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6186 * so the tree did not actually change and there is nothing for us to do
6187 */
6188 if (unlinked_nodes && ctx_node) {
6189 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6190 rc = -1;
6191 goto cleanup;
6192 }
6193 }
6194
Radek Krejci03b71f72016-03-16 11:10:09 +01006195 if (rc) {
6196 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006197 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006198 }
Radek Krejci51093642016-03-29 10:14:59 +02006199 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006200 }
6201
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006202 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006203 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006204 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006205 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006206 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006207 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006208 } else {
6209 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6210 goto cleanup;
6211 }
Michal Vaskocf024702015-10-08 15:01:42 +02006212 }
Radek Krejci51093642016-03-29 10:14:59 +02006213
6214 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006215 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006216 }
6217
Michal Vasko90fc2a32016-08-24 15:58:58 +02006218 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006219 }
6220
Radek Krejci0b7704f2016-03-18 12:16:14 +01006221 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006222
Radek Krejci51093642016-03-29 10:14:59 +02006223cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006224 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006225 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006226
Radek Krejci46165822016-08-26 14:06:27 +02006227 if (result) {
6228 if (node->when_status & LYD_WHEN_TRUE) {
6229 *result = 1;
6230 } else {
6231 *result = 0;
6232 }
6233 }
6234
Radek Krejci51093642016-03-29 10:14:59 +02006235 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006236}
6237
Radek Krejcicbb473e2016-09-16 14:48:32 +02006238static int
6239check_leafref_features(struct lys_type *type)
6240{
6241 struct lys_node *iter;
6242 struct ly_set *src_parents, *trg_parents, *features;
6243 unsigned int i, j, size, x;
6244 int ret = EXIT_SUCCESS;
6245
6246 assert(type->parent);
6247
6248 src_parents = ly_set_new();
6249 trg_parents = ly_set_new();
6250 features = ly_set_new();
6251
6252 /* get parents chain of source (leafref) */
6253 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
6254 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6255 continue;
6256 }
6257 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6258 }
6259 /* get parents chain of target */
6260 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
6261 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6262 continue;
6263 }
6264 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6265 }
6266
6267 /* compare the features used in if-feature statements in the rest of both
6268 * chains of parents. The set of features used for target must be a subset
6269 * of features used for the leafref. This is not a perfect, we should compare
6270 * the truth tables but it could require too much resources, so we simplify that */
6271 for (i = 0; i < src_parents->number; i++) {
6272 iter = src_parents->set.s[i]; /* shortcut */
6273 if (!iter->iffeature_size) {
6274 continue;
6275 }
6276 for (j = 0; j < iter->iffeature_size; j++) {
6277 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6278 for (; size; size--) {
6279 if (!iter->iffeature[j].features[size - 1]) {
6280 /* not yet resolved feature, postpone this check */
6281 ret = EXIT_FAILURE;
6282 goto cleanup;
6283 }
6284 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6285 }
6286 }
6287 }
6288 x = features->number;
6289 for (i = 0; i < trg_parents->number; i++) {
6290 iter = trg_parents->set.s[i]; /* shortcut */
6291 if (!iter->iffeature_size) {
6292 continue;
6293 }
6294 for (j = 0; j < iter->iffeature_size; j++) {
6295 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6296 for (; size; size--) {
6297 if (!iter->iffeature[j].features[size - 1]) {
6298 /* not yet resolved feature, postpone this check */
6299 ret = EXIT_FAILURE;
6300 goto cleanup;
6301 }
6302 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6303 /* the feature is not present in features set of target's parents chain */
6304 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006305 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006306 "Leafref is not conditional based on \"%s\" feature as its target.",
6307 iter->iffeature[j].features[size - 1]->name);
6308 ret = -1;
6309 goto cleanup;
6310 }
6311 }
6312 }
6313 }
6314
6315cleanup:
6316 ly_set_free(features);
6317 ly_set_free(src_parents);
6318 ly_set_free(trg_parents);
6319
6320 return ret;
6321}
6322
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006323/**
Michal Vaskobb211122015-08-19 14:03:11 +02006324 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006325 *
6326 * @param[in] mod Main module.
6327 * @param[in] item Item to resolve. Type determined by \p type.
6328 * @param[in] type Type of the unresolved item.
6329 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006330 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006331 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006332 *
6333 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6334 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006335static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006336resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006337 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006338{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006339 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006340 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006341 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006342 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006343 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006344 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006345
Radek Krejcic79c6b12016-07-26 15:11:49 +02006346 struct ly_set *refs, *procs;
6347 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006348 struct lys_ident *ident;
6349 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006350 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006351 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006352 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006353 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006354 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006355 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006356 struct lys_ext_instance *ext, **extlist;
6357 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006358
6359 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006360 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006361 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006362 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006363 ident = item;
6364
Radek Krejci018f1f52016-08-03 16:01:20 +02006365 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006366 break;
6367 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006368 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006369 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006370 stype = item;
6371
Radek Krejci018f1f52016-08-03 16:01:20 +02006372 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006373 break;
6374 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006375 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006376 stype = item;
6377
Radek Krejci2f12f852016-01-08 12:59:57 +01006378 /* HACK - when there is no parent, we are in top level typedef and in that
6379 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6380 * know it via tpdf_flag */
6381 if (!node) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006382 parent_type = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006383 node = (struct lys_node *)stype->parent;
6384 }
6385
Radek Krejci27fe55e2016-09-13 17:13:35 +02006386 if (!lys_node_module(node)->implemented) {
6387 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006388 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006389 rc = 0;
6390 break;
6391 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01006392 rc = resolve_path_arg_schema(stype->info.lref.path, node, parent_type,
Michal Vasko1e62a092015-12-01 12:27:20 +01006393 (const struct lys_node **)&stype->info.lref.target);
Radek Krejci8d6b7422017-02-03 14:42:13 +01006394 if (!parent_type && !rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006395 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006396 /* check if leafref and its target are under a common if-features */
6397 rc = check_leafref_features(stype);
6398 if (rc) {
6399 break;
6400 }
6401
Radek Krejci46c4cd72016-01-21 15:13:52 +01006402 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006403 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6404 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006405 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006406 }
6407
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006408 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006409 case UNRES_TYPE_DER_EXT:
6410 parent_type++;
6411 /* no break */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006412 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006413 parent_type++;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006414 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006415 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006416 /* parent */
6417 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006418 stype = item;
6419
Michal Vasko88c29542015-11-27 14:57:53 +01006420 /* HACK type->der is temporarily unparsed type statement */
6421 yin = (struct lyxml_elem *)stype->der;
6422 stype->der = NULL;
6423
Pavol Vicana0e4e672016-02-24 12:20:04 +01006424 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6425 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006426 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006427
6428 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006429 /* may try again later */
6430 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006431 } else {
6432 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006433 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006434 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006435 }
6436
Michal Vasko88c29542015-11-27 14:57:53 +01006437 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006438 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006439 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006440 /* we need to always be able to free this, it's safe only in this case */
6441 lyxml_free(mod->ctx, yin);
6442 } else {
6443 /* may try again later, put all back how it was */
6444 stype->der = (struct lys_tpdf *)yin;
6445 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006446 }
Radek Krejcic13db382016-08-16 10:52:42 +02006447 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006448 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006449 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006450 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6451 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006452 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006453 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6454 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6455 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6456 * 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 +02006457 * 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 +02006458 * of the type's base member. */
6459 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6460 if (par_grp) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01006461#if __BYTE_ORDER == __LITTLE_ENDIAN
6462 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
6463#else
6464 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
6465#endif
Radek Krejci9b6aad22016-09-20 15:55:51 +02006466 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006467 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006468 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006469 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006470 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006471 iff_data = str_snode;
6472 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006473 if (!rc) {
6474 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006475 if (iff_data->infeature) {
6476 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6477 feat = *((struct lys_feature **)item);
6478 if (!feat->depfeatures) {
6479 feat->depfeatures = ly_set_new();
6480 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006481 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006482 }
6483 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006484 lydict_remove(mod->ctx, iff_data->fname);
6485 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006486 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006487 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006488 case UNRES_FEATURE:
6489 feat = (struct lys_feature *)item;
6490
6491 if (feat->iffeature_size) {
6492 refs = ly_set_new();
6493 procs = ly_set_new();
6494 ly_set_add(procs, feat, 0);
6495
6496 while (procs->number) {
6497 ref = procs->set.g[procs->number - 1];
6498 ly_set_rm_index(procs, procs->number - 1);
6499
6500 for (i = 0; i < ref->iffeature_size; i++) {
6501 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6502 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006503 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006504 if (ref->iffeature[i].features[j - 1] == feat) {
6505 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6506 goto featurecheckdone;
6507 }
6508
6509 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6510 k = refs->number;
6511 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6512 /* not yet seen feature, add it for processing */
6513 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6514 }
6515 }
6516 } else {
6517 /* forward reference */
6518 rc = EXIT_FAILURE;
6519 goto featurecheckdone;
6520 }
6521 }
6522
6523 }
6524 }
6525 rc = EXIT_SUCCESS;
6526
6527featurecheckdone:
6528 ly_set_free(refs);
6529 ly_set_free(procs);
6530 }
6531
6532 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006533 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006534 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006535 break;
6536 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006537 stype = item;
6538
Radek Krejci51673202016-11-01 17:00:32 +01006539 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006540 break;
6541 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006542 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006543 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006544 choic = item;
6545
Radek Krejcie00d2312016-08-12 15:27:49 +02006546 if (!choic->dflt) {
6547 choic->dflt = resolve_choice_dflt(choic, expr);
6548 }
Michal Vasko7955b362015-09-04 14:18:15 +02006549 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006550 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006551 } else {
6552 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006553 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006554 break;
6555 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006556 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006557 break;
6558 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006559 unique_info = (struct unres_list_uniq *)item;
6560 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006561 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006562 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006563 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006564 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006565 case UNRES_XPATH:
6566 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006567 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006568 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006569 case UNRES_EXT:
6570 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006571 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006572 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006573 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006574 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006575 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006576 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006577 if (eplugin) {
6578 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006579 u = malloc(sizeof *u);
6580 (*u) = ext_data->ext_index;
6581 unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u);
Radek Krejci80056d52017-01-05 13:13:33 +01006582 }
6583 }
Radek Krejci79685c92017-02-17 10:49:43 +01006584 }
6585 if (!rc || rc == -1) {
6586 /* cleanup on success or fatal error */
6587 if (ext_data->datatype == LYS_IN_YIN) {
6588 /* YIN */
6589 lyxml_free(mod->ctx, ext_data->data.yin);
6590 } else {
6591 /* TODO YANG */
6592 free(ext_data->data.yang);
6593 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006594 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006595 }
6596 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006597 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006598 u = (uint8_t *)str_snode;
6599 ext = (*(struct lys_ext_instance ***)item)[*u];
6600 free(u);
6601
Radek Krejci80056d52017-01-05 13:13:33 +01006602 eplugin = ext->def->plugin;
6603
6604 /* inherit */
6605 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6606 root = (struct lys_node *)ext->parent;
6607 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6608 LY_TREE_DFS_BEGIN(root->child, next, node) {
6609 /* first, check if the node already contain instance of the same extension,
6610 * in such a case we won't inherit. In case the node was actually defined as
6611 * augment data, we are supposed to check the same way also the augment node itself */
6612 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6613 goto inherit_dfs_sibling;
6614 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6615 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6616 goto inherit_dfs_sibling;
6617 }
6618
6619 if (eplugin->check_inherit) {
6620 /* we have a callback to check the inheritance, use it */
6621 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6622 case 0:
6623 /* yes - continue with the inheriting code */
6624 break;
6625 case 1:
6626 /* no - continue with the node's sibling */
6627 goto inherit_dfs_sibling;
6628 case 2:
6629 /* no, but continue with the children, just skip the inheriting code for this node */
6630 goto inherit_dfs_child;
6631 default:
6632 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6633 ext->def->module->name, ext->def->name, rc);
6634 }
6635 }
6636
6637 /* inherit the extension */
6638 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
6639 if (!extlist) {
6640 LOGMEM;
6641 return -1;
6642 }
6643 extlist[node->ext_size] = malloc(sizeof **extlist);
6644 if (!extlist[node->ext_size]) {
6645 LOGMEM;
6646 node->ext = extlist;
6647 return -1;
6648 }
6649 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6650 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6651
6652 node->ext = extlist;
6653 node->ext_size++;
6654
6655inherit_dfs_child:
6656 /* modification of - select element for the next run - children first */
6657 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6658 next = NULL;
6659 } else {
6660 next = node->child;
6661 }
6662 if (!next) {
6663inherit_dfs_sibling:
6664 /* no children, try siblings */
6665 next = node->next;
6666 }
6667 while (!next) {
6668 /* go to the parent */
6669 node = lys_parent(node);
6670
6671 /* we are done if we are back in the root (the starter's parent */
6672 if (node == root) {
6673 break;
6674 }
6675
6676 /* parent is already processed, go to its sibling */
6677 next = node->next;
6678 }
6679 }
6680 }
6681 }
6682
6683 /* final check */
6684 if (eplugin->check_result) {
6685 if ((*eplugin->check_result)(ext)) {
6686 return -1;
6687 }
6688 }
6689
6690 rc = 0;
6691 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006692 default:
6693 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006694 break;
6695 }
6696
Radek Krejci54081ce2016-08-12 15:21:47 +02006697 if (has_str && !rc) {
6698 /* the string is no more needed in case of success.
6699 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006700 lydict_remove(mod->ctx, str_snode);
6701 }
6702
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006703 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006704}
6705
Michal Vaskof02e3742015-08-05 16:27:02 +02006706/* logs directly */
6707static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006708print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006709{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006710 struct lyxml_elem *xml;
6711 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006712 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006713 const char *name = NULL;
6714 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006715
Michal Vaskof02e3742015-08-05 16:27:02 +02006716 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006717 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006718 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006719 break;
6720 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006721 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006722 break;
6723 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006724 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6725 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006726 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006727 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006728 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006729 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006730 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6731 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006732 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006733 } else {
6734 LY_TREE_FOR(xml->attr, attr) {
6735 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006736 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006737 break;
6738 }
6739 }
6740 assert(attr);
6741 }
Radek Krejcie534c132016-11-23 13:32:31 +01006742 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006743 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006744 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006745 iff_data = str_node;
6746 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006747 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006748 case UNRES_FEATURE:
6749 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6750 ((struct lys_feature *)item)->name);
6751 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006752 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006753 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006754 break;
6755 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006756 if (str_node) {
6757 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6758 } /* else no default value in the type itself, but we are checking some restrictions against
6759 * possible default value of some base type. The failure is caused by not resolved base type,
6760 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006761 break;
6762 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006763 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006764 break;
6765 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006766 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006767 break;
6768 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006769 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006770 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006771 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006772 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6773 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006774 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006775 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006776 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6777 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006778 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006779 case UNRES_EXT:
6780 extinfo = (struct unres_ext *)str_node;
6781 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6782 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6783 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006784 default:
6785 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006786 break;
6787 }
6788}
6789
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006790/**
Michal Vaskobb211122015-08-19 14:03:11 +02006791 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006792 *
6793 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006794 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006795 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006796 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006797 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006798int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006799resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006800{
Radek Krejci010e54b2016-03-15 09:40:34 +01006801 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006802 struct lyxml_elem *yin;
6803 struct yang_type *yang;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006804 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006805
6806 assert(unres);
6807
Michal Vaskoe8734262016-09-29 14:12:06 +02006808 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006809 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006810
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006811 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006812 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006813 unres_count = 0;
6814 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006815
6816 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006817 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006818 * if-features are resolved here to make sure that we will have all if-features for
6819 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006820 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006821 continue;
6822 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006823 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006824 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006825
Michal Vasko88c29542015-11-27 14:57:53 +01006826 ++unres_count;
Michal Vasko769f8032017-01-24 13:11:55 +01006827 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006828 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006829 unres->type[i] = UNRES_RESOLVED;
6830 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006831 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006832 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006833 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006834 /* print the error */
Michal Vasko769f8032017-01-24 13:11:55 +01006835 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006836 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006837 } else {
6838 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006839 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006840 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006841 }
Michal Vasko88c29542015-11-27 14:57:53 +01006842 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006843
Michal Vasko88c29542015-11-27 14:57:53 +01006844 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006845 /* just print the errors */
6846 ly_vlog_hide(0);
6847
6848 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006849 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006850 continue;
6851 }
Michal Vasko769f8032017-01-24 13:11:55 +01006852 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejci63fc0962017-02-15 13:20:18 +01006853 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006854 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6855 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6856 yang =(struct yang_type *)yin;
6857 ((struct lys_type *)unres->item[i])->base = yang->base;
6858 if (yang->base == LY_TYPE_UNION) {
6859 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6860 }
6861 lydict_remove(mod->ctx, yang->name);
6862 free(yang);
6863 } else {
6864 lyxml_free(mod->ctx, yin);
6865 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006866 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006867 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006868 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006869 }
6870
Radek Krejci07d0fb92017-01-13 14:11:05 +01006871 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006872 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006873 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006874 continue;
6875 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006876
Michal Vasko769f8032017-01-24 13:11:55 +01006877 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006878 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006879 if (unres->type[i] == UNRES_LIST_UNIQ) {
6880 /* free the allocated structure */
6881 free(unres->item[i]);
6882 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006883 unres->type[i] = UNRES_RESOLVED;
6884 ++resolved;
6885 } else if (rc == -1) {
6886 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006887 /* print the error */
Michal Vasko769f8032017-01-24 13:11:55 +01006888 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006889 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006890 }
6891 }
6892
Radek Krejci010e54b2016-03-15 09:40:34 +01006893 ly_vlog_hide(0);
6894
Radek Krejci80056d52017-01-05 13:13:33 +01006895 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6896 for (i = 0; i < unres->count; ++i) {
6897 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6898 continue;
6899 }
6900
Radek Krejcicbba57c2017-01-24 13:43:20 +01006901 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006902 if (rc == 0) {
6903 unres->type[i] = UNRES_RESOLVED;
6904 ++resolved;
6905 }
6906 }
6907
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006908 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006909 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6910 * all the validation errors
6911 */
6912 for (i = 0; i < unres->count; ++i) {
6913 if (unres->type[i] == UNRES_RESOLVED) {
6914 continue;
6915 }
Michal Vasko769f8032017-01-24 13:11:55 +01006916 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006917 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006918 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006919 unres->type[i] = UNRES_RESOLVED;
6920 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006921 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006922 }
Radek Krejcib3142312016-11-09 11:04:12 +01006923 if (resolved < unres->count) {
6924 return -1;
6925 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006926 }
6927
Michal Vaskoe8734262016-09-29 14:12:06 +02006928 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006929 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006930 return EXIT_SUCCESS;
6931}
6932
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006933/**
Michal Vaskobb211122015-08-19 14:03:11 +02006934 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006935 *
6936 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006937 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006938 * @param[in] item Item to resolve. Type determined by \p type.
6939 * @param[in] type Type of the unresolved item.
6940 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006941 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006942 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006943 */
6944int
Radek Krejci48464ed2016-03-17 15:44:09 +01006945unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6946 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006947{
Radek Krejci54081ce2016-08-12 15:21:47 +02006948 int rc;
6949 const char *dictstr;
6950
6951 dictstr = lydict_insert(mod->ctx, str, 0);
6952 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6953
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006954 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006955 lydict_remove(mod->ctx, dictstr);
6956 }
6957 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006958}
6959
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006960/**
Michal Vaskobb211122015-08-19 14:03:11 +02006961 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006962 *
6963 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006964 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006965 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006966 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006967 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006968 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006969 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6970 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006971 */
6972int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006973unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006974 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006975{
Michal Vaskoef486d72016-09-27 12:10:44 +02006976 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006977 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006978 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006979
Michal Vasko9bf425b2015-10-22 11:42:03 +02006980 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6981 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006982
Radek Krejci850a5de2016-11-08 14:06:40 +01006983 /* check for duplicities in unres */
6984 for (u = 0; u < unres->count; u++) {
6985 if (unres->type[u] == type && unres->item[u] == item &&
6986 unres->str_snode[u] == snode && unres->module[u] == mod) {
6987 /* duplication, will be resolved later */
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006988 return -2;
Radek Krejci850a5de2016-11-08 14:06:40 +01006989 }
6990 }
6991
Radek Krejci80056d52017-01-05 13:13:33 +01006992 if (type != UNRES_EXT_FINALIZE) {
6993 /* extension finalization is not even tried when adding the item into the inres list */
Michal Vaskoef486d72016-09-27 12:10:44 +02006994
Radek Krejci80056d52017-01-05 13:13:33 +01006995 if (*ly_vlog_hide_location()) {
6996 log_hidden = 1;
6997 } else {
6998 log_hidden = 0;
6999 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007000 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01007001 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01007002 if (!log_hidden) {
7003 ly_vlog_hide(0);
7004 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007005
Radek Krejci80056d52017-01-05 13:13:33 +01007006 if (rc != EXIT_FAILURE) {
7007 if (rc == -1 && ly_errno == LY_EVALID) {
7008 ly_err_repeat();
7009 }
7010 if (type == UNRES_LIST_UNIQ) {
7011 /* free the allocated structure */
7012 free(item);
7013 } else if (rc == -1 && type == UNRES_IFFEAT) {
7014 /* free the allocated resources */
7015 free(*((char **)item));
7016 }
7017 return rc;
7018 } else {
7019 /* erase info about validation errors */
7020 ly_err_clean(1);
7021 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007022
Radek Krejci80056d52017-01-05 13:13:33 +01007023 print_unres_schema_item_fail(item, type, snode);
7024
7025 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7026 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7027 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7028 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7029 lyxml_unlink_elem(mod->ctx, yin, 1);
7030 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7031 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007032 }
Michal Vasko88c29542015-11-27 14:57:53 +01007033 }
7034
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007035 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007036 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
7037 if (!unres->item) {
7038 LOGMEM;
7039 return -1;
7040 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007041 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007042 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
7043 if (!unres->type) {
7044 LOGMEM;
7045 return -1;
7046 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007047 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007048 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
7049 if (!unres->str_snode) {
7050 LOGMEM;
7051 return -1;
7052 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007053 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007054 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
7055 if (!unres->module) {
7056 LOGMEM;
7057 return -1;
7058 }
7059 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007060
Michal Vasko3767fb22016-07-21 12:10:57 +02007061 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007062}
7063
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007064/**
Michal Vaskobb211122015-08-19 14:03:11 +02007065 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007066 *
7067 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007068 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007069 * @param[in] item Old item to be resolved.
7070 * @param[in] type Type of the old unresolved item.
7071 * @param[in] new_item New item to use in the duplicate.
7072 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007073 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007074 */
Michal Vaskodad19402015-08-06 09:51:53 +02007075int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007076unres_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 +02007077{
7078 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007079 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007080 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007081
Michal Vaskocf024702015-10-08 15:01:42 +02007082 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007083
Radek Krejcid09d1a52016-08-11 14:05:45 +02007084 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7085 if (type == UNRES_LIST_UNIQ) {
7086 aux_uniq.list = item;
7087 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7088 item = &aux_uniq;
7089 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007090 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007091
7092 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007093 if (type == UNRES_LIST_UNIQ) {
7094 free(new_item);
7095 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007096 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007097 }
7098
Radek Krejcic79c6b12016-07-26 15:11:49 +02007099 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007100 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007101 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007102 LOGINT;
7103 return -1;
7104 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007105 } else if (type == UNRES_IFFEAT) {
7106 /* duplicate unres_iffeature_data */
7107 iff_data = malloc(sizeof *iff_data);
7108 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7109 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7110 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7111 LOGINT;
7112 return -1;
7113 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007114 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007115 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007116 LOGINT;
7117 return -1;
7118 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007119 }
Michal Vaskodad19402015-08-06 09:51:53 +02007120
7121 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007122}
7123
Michal Vaskof02e3742015-08-05 16:27:02 +02007124/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007125int
Michal Vasko878e38d2016-09-05 12:17:53 +02007126unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007127{
Michal Vasko878e38d2016-09-05 12:17:53 +02007128 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007129 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007130
Radek Krejciddddd0d2017-01-20 15:20:46 +01007131 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007132 i = start_on_backwards;
7133 } else {
7134 i = unres->count - 1;
7135 }
7136 for (; i > -1; i--) {
7137 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007138 continue;
7139 }
7140 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007141 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007142 break;
7143 }
7144 } else {
7145 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7146 aux_uniq2 = (struct unres_list_uniq *)item;
7147 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007148 break;
7149 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007150 }
7151 }
7152
Michal Vasko878e38d2016-09-05 12:17:53 +02007153 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007154}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007155
Michal Vaskoede9c472016-06-07 09:38:15 +02007156static void
7157unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7158{
7159 struct lyxml_elem *yin;
7160 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007161 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007162
7163 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007164 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007165 case UNRES_TYPE_DER:
7166 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7167 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7168 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007169 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007170 lydict_remove(ctx, yang->name);
7171 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007172 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7173 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7174 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007175 } else {
7176 lyxml_free(ctx, yin);
7177 }
7178 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007179 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007180 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7181 lydict_remove(ctx, iff_data->fname);
7182 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007183 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007184 case UNRES_IDENT:
7185 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007186 case UNRES_CHOICE_DFLT:
7187 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007188 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7189 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007190 case UNRES_LIST_UNIQ:
7191 free(unres->item[i]);
7192 break;
PavolVicanc1807262017-01-31 18:00:27 +01007193 case UNRES_EXT:
7194 free(unres->str_snode[i]);
7195 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007196 default:
7197 break;
7198 }
7199 unres->type[i] = UNRES_RESOLVED;
7200}
7201
Michal Vasko88c29542015-11-27 14:57:53 +01007202void
Radek Krejcic071c542016-01-27 14:57:51 +01007203unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01007204{
7205 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007206 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007207
Radek Krejcic071c542016-01-27 14:57:51 +01007208 if (!unres || !(*unres)) {
7209 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007210 }
7211
Radek Krejcic071c542016-01-27 14:57:51 +01007212 assert(module || (*unres)->count == 0);
7213
7214 for (i = 0; i < (*unres)->count; ++i) {
7215 if ((*unres)->module[i] != module) {
7216 if ((*unres)->type[i] != UNRES_RESOLVED) {
7217 unresolved++;
7218 }
7219 continue;
7220 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007221
7222 /* free heap memory for the specific item */
7223 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007224 }
7225
Michal Vaskoede9c472016-06-07 09:38:15 +02007226 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01007227 if (!module || (!unresolved && !module->type)) {
7228 free((*unres)->item);
7229 free((*unres)->type);
7230 free((*unres)->str_snode);
7231 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007232 free((*unres));
7233 (*unres) = NULL;
7234 }
Michal Vasko88c29542015-11-27 14:57:53 +01007235}
7236
Michal Vasko3cfa3182017-01-17 10:00:58 +01007237static int
7238check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7239{
7240 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007241 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007242 char *buf;
7243
7244 for (op_node = lys_parent(sleaf);
7245 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7246 op_node = lys_parent(op_node));
7247
7248 if (op_node && lys_parent(op_node)) {
7249 /* nested operation - any absolute path is external */
7250 return 1;
7251 }
7252
7253 /* get the first node from the instid */
7254 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7255 if (!buf) {
7256 LOGMEM;
7257 return -1;
7258 }
7259
7260 /* there is a predicate, remove it */
7261 if (buf[strlen(buf) - 1] == ']') {
7262 assert(strchr(buf, '['));
7263 *strchr(buf, '[') = '\0';
7264 }
7265
7266 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01007267 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007268 if (!set || !set->number) {
7269 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007270 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007271 return 1;
7272 }
7273 free(buf);
7274
Michal Vasko3c777092017-01-17 14:10:09 +01007275 first_node = set->set.s[0];
7276 ly_set_free(set);
7277
Michal Vasko3cfa3182017-01-17 10:00:58 +01007278 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7279
7280 if (op_node) {
7281 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007282 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007283 assert(set->number == 1);
7284 return 0;
7285 } else {
7286 return 1;
7287 }
7288 }
7289
7290 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7291 * this itself), so we say it's not external */
7292 return 0;
7293}
7294
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007295/**
7296 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7297 *
7298 * @param[in] data Data node where the path is used
7299 * @param[in] path Instance-identifier node value.
7300 * @param[in,out] ret Resolved instance or NULL.
7301 *
7302 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7303 */
7304static int
7305resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7306{
7307 int i = 0, j;
7308 const struct lys_module *mod;
7309 struct ly_ctx *ctx = data->schema->module->ctx;
7310 const char *model, *name;
7311 char *str;
7312 int mod_len, name_len, has_predicate;
7313 struct unres_data node_match;
7314
7315 memset(&node_match, 0, sizeof node_match);
7316 *ret = NULL;
7317
7318 /* we need root to resolve absolute path */
7319 for (; data->parent; data = data->parent);
7320 /* we're still parsing it and the pointer is not correct yet */
7321 if (data->prev) {
7322 for (; data->prev->next; data = data->prev);
7323 }
7324
7325 /* search for the instance node */
7326 while (path[i]) {
7327 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7328 if (j <= 0) {
7329 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7330 goto error;
7331 }
7332 i += j;
7333
7334 str = strndup(model, mod_len);
7335 if (!str) {
7336 LOGMEM;
7337 goto error;
7338 }
7339 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007340 if (ctx->data_clb) {
7341 if (!mod) {
7342 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7343 } else if (!mod->implemented) {
7344 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7345 }
7346 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007347 free(str);
7348
Michal Vaskof53187d2017-01-13 13:23:14 +01007349 if (!mod || !mod->implemented || mod->disabled) {
7350 break;
7351 }
7352
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007353 if (resolve_data(mod, name, name_len, data, &node_match)) {
7354 /* no instance exists */
7355 break;
7356 }
7357
7358 if (has_predicate) {
7359 /* we have predicate, so the current results must be list or leaf-list */
7360 j = resolve_predicate(&path[i], &node_match);
7361 if (j < 1) {
7362 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7363 goto error;
7364 }
7365 i += j;
7366
7367 if (!node_match.count) {
7368 /* no instance exists */
7369 break;
7370 }
7371 }
7372 }
7373
7374 if (!node_match.count) {
7375 /* no instance exists */
7376 if (req_inst > -1) {
7377 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7378 return EXIT_FAILURE;
7379 }
7380 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7381 return EXIT_SUCCESS;
7382 } else if (node_match.count > 1) {
7383 /* instance identifier must resolve to a single node */
7384 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7385 goto error;
7386 } else {
7387 /* we have required result, remember it and cleanup */
7388 *ret = node_match.node[0];
7389 free(node_match.node);
7390 return EXIT_SUCCESS;
7391 }
7392
7393error:
7394 /* cleanup */
7395 free(node_match.node);
7396 return -1;
7397}
7398
7399static int
7400resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007401{
Radek Krejci7de36cf2016-09-12 16:18:50 +02007402 struct unres_data matches;
7403 uint32_t i;
7404
Radek Krejci9b6aad22016-09-20 15:55:51 +02007405 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007406 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007407 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007408
7409 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007410 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007411 return -1;
7412 }
7413
7414 /* check that value matches */
7415 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007416 /* not that the value is already in canonical form since the parsers does the conversion,
7417 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007418 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007419 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007420 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007421 break;
7422 }
7423 }
7424
7425 free(matches.node);
7426
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007427 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007428 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007429 if (req_inst > -1) {
7430 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007431 return EXIT_FAILURE;
7432 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007433 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 +02007434 }
7435 }
7436
7437 return EXIT_SUCCESS;
7438}
7439
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007440/* 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 +01007441int
7442resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7443 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007444{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007445 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007446 struct lyd_node *ret;
7447 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007448 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007449
7450 assert(type->base == LY_TYPE_UNION);
7451
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007452 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7453 /* either NULL or instid previously converted to JSON */
7454 json_val = leaf->value.string;
7455 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007456
Michal Vaskofd6c6502017-01-06 12:15:41 +01007457 if (store) {
7458 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7459 free(leaf->value.bit);
7460 }
7461 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007462 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007463
7464 /* turn logging off, we are going to try to validate the value with all the types in order */
7465 hidden = *ly_vlog_hide_location();
7466 ly_vlog_hide(1);
7467
7468 t = NULL;
7469 found = 0;
7470 while ((t = lyp_get_next_union_type(type, t, &found))) {
7471 found = 0;
7472
7473 switch (t->base) {
7474 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007475 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7476 req_inst = -1;
7477 } else {
7478 req_inst = t->info.lref.req;
7479 }
7480
7481 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007482 if (store) {
7483 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7484 /* valid resolved */
7485 leaf->value.leafref = ret;
7486 leaf->value_type = LY_TYPE_LEAFREF;
7487 } else {
7488 /* valid unresolved */
7489 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
7490 return -1;
7491 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007492 }
7493 }
7494
7495 success = 1;
7496 }
7497 break;
7498 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007499 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7500 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7501 req_inst = -1;
7502 } else {
7503 req_inst = t->info.inst.req;
7504 }
7505
Michal Vaskod3a03112017-01-23 09:56:02 +01007506 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007507 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007508 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007509 /* valid resolved */
7510 leaf->value.instance = ret;
7511 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007512
Michal Vaskofd6c6502017-01-06 12:15:41 +01007513 if (json_val) {
7514 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7515 leaf->value_str = json_val;
7516 json_val = NULL;
7517 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007518 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007519 /* valid unresolved */
7520 if (json_val) {
7521 /* put the JSON val back */
7522 leaf->value.string = json_val;
7523 json_val = NULL;
7524 } else {
7525 leaf->value.instance = NULL;
7526 }
7527 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007528 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007529 }
7530
7531 success = 1;
7532 }
7533 break;
7534 default:
Michal Vaskofd6c6502017-01-06 12:15:41 +01007535 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007536 success = 1;
7537 }
7538 break;
7539 }
7540
7541 if (success) {
7542 break;
7543 }
7544
7545 /* erase information about errors - they are false or irrelevant
7546 * and will be replaced by a single error messages */
7547 ly_err_clean(1);
7548
7549 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007550 if (store) {
7551 if (t->base == LY_TYPE_BITS) {
7552 free(leaf->value.bit);
7553 }
7554 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007555 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007556 }
7557
7558 /* turn logging back on */
7559 if (!hidden) {
7560 ly_vlog_hide(0);
7561 }
7562
7563 if (json_val) {
7564 if (!success) {
7565 /* put the value back for now */
7566 assert(leaf->value_type == LY_TYPE_UNION);
7567 leaf->value.string = json_val;
7568 } else {
7569 /* value was ultimately useless, but we could not have known */
7570 lydict_remove(leaf->schema->module->ctx, json_val);
7571 }
7572 }
7573
Michal Vaskofd6c6502017-01-06 12:15:41 +01007574 if (success) {
7575 if (resolved_type) {
7576 *resolved_type = t;
7577 }
7578 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007579 /* not found and it is required */
7580 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007581 return EXIT_FAILURE;
7582 }
7583
7584 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007585
Radek Krejci9b6aad22016-09-20 15:55:51 +02007586}
7587
Michal Vasko8bcdf292015-08-19 14:04:43 +02007588/**
7589 * @brief Resolve a single unres data item. Logs directly.
7590 *
Michal Vaskocf024702015-10-08 15:01:42 +02007591 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007592 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007593 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007594 *
7595 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7596 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007597int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007598resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007599{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007600 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007601 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007602 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007603 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007604
Michal Vasko83a6c462015-10-08 16:43:53 +02007605 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007606 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007607
Michal Vaskocf024702015-10-08 15:01:42 +02007608 switch (type) {
7609 case UNRES_LEAFREF:
7610 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007611 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007612 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7613 req_inst = -1;
7614 } else {
7615 req_inst = sleaf->type.info.lref.req;
7616 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007617 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7618 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007619 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007620 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007621 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7622 free(leaf->value.bit);
7623 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007624 leaf->value.leafref = ret;
7625 leaf->value_type = LY_TYPE_LEAFREF;
7626 } else {
7627 /* valid unresolved */
7628 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
7629 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
7630 return -1;
7631 }
7632 }
7633 }
7634 leaf->validity &= ~LYD_VAL_LEAFREF;
7635 } else {
7636 return rc;
7637 }
7638 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007639
Michal Vaskocf024702015-10-08 15:01:42 +02007640 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007641 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007642 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7643 if (ext_dep == -1) {
7644 return -1;
7645 }
7646
7647 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7648 req_inst = -1;
7649 } else {
7650 req_inst = sleaf->type.info.inst.req;
7651 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007652 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7653 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007654 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007655 /* valid resolved */
7656 leaf->value.instance = ret;
7657 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007658 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007659 /* valid unresolved */
7660 leaf->value.instance = NULL;
7661 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007662 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007663 } else {
7664 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007665 }
Michal Vaskocf024702015-10-08 15:01:42 +02007666 break;
7667
Radek Krejci7de36cf2016-09-12 16:18:50 +02007668 case UNRES_UNION:
7669 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007670 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007671
Michal Vaskocf024702015-10-08 15:01:42 +02007672 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007673 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007674 return rc;
7675 }
7676 break;
7677
Michal Vaskobf19d252015-10-08 15:39:17 +02007678 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007679 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007680 return rc;
7681 }
7682 break;
7683
7684 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007685 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007686 return rc;
7687 }
7688 break;
7689
Michal Vaskocf024702015-10-08 15:01:42 +02007690 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007691 LOGINT;
7692 return -1;
7693 }
7694
7695 return EXIT_SUCCESS;
7696}
7697
7698/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007699 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007700 *
7701 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007702 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007703 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007704 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007705 */
7706int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007707unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007708{
Radek Krejci03b71f72016-03-16 11:10:09 +01007709 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007710 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007711 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007712
Radek Krejci03b71f72016-03-16 11:10:09 +01007713 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007714 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7715 if (!unres->node) {
7716 LOGMEM;
7717 return -1;
7718 }
Michal Vaskocf024702015-10-08 15:01:42 +02007719 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007720 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7721 if (!unres->type) {
7722 LOGMEM;
7723 return -1;
7724 }
Michal Vaskocf024702015-10-08 15:01:42 +02007725 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007726
Radek Krejci0b7704f2016-03-18 12:16:14 +01007727 if (type == UNRES_WHEN) {
7728 /* remove previous result */
7729 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007730 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007731
7732 return EXIT_SUCCESS;
7733}
7734
7735/**
7736 * @brief Resolve every unres data item in the structure. Logs directly.
7737 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007738 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7739 * unresolved leafrefs/instids are accepted).
7740 *
7741 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7742 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007743 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007744 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7745 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007746 *
7747 * @return EXIT_SUCCESS on success, -1 on error.
7748 */
7749int
Radek Krejci082c84f2016-10-17 16:33:06 +02007750resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007751{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007752 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007753 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007754 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007755
Radek Krejci082c84f2016-10-17 16:33:06 +02007756 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007757 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007758
7759 if (!unres->count) {
7760 return EXIT_SUCCESS;
7761 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007762
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007763 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 +01007764 ignore_fail = 1;
7765 } else if (options & LYD_OPT_NOEXTDEPS) {
7766 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007767 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007768 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007769 }
7770
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007771 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007772 ly_vlog_hide(1);
7773
Radek Krejci0b7704f2016-03-18 12:16:14 +01007774 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007775 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007776 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007777 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007778 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007779 if (unres->type[i] != UNRES_WHEN) {
7780 continue;
7781 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007782 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007783 /* count when-stmt nodes in unres list */
7784 when_stmt++;
7785 }
7786
7787 /* resolve when condition only when all parent when conditions are already resolved */
7788 for (parent = unres->node[i]->parent;
7789 parent && LYD_WHEN_DONE(parent->when_status);
7790 parent = parent->parent) {
7791 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7792 /* the parent node was already unlinked, do not resolve this node,
7793 * it will be removed anyway, so just mark it as resolved
7794 */
7795 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7796 unres->type[i] = UNRES_RESOLVED;
7797 resolved++;
7798 break;
7799 }
7800 }
7801 if (parent) {
7802 continue;
7803 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007804
Michal Vasko3cfa3182017-01-17 10:00:58 +01007805 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007806 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007807 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007808 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007809 /* false when condition */
7810 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007811 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007812 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007813 } /* follows else */
7814
Radek Krejci0c0086a2016-03-24 15:20:28 +01007815 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7816 /* if it has parent non-presence containers that would be empty, we should actually
7817 * remove the container
7818 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007819 for (parent = unres->node[i];
7820 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7821 parent = parent->parent) {
7822 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7823 /* presence container */
7824 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007825 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007826 if (parent->next || parent->prev != parent) {
7827 /* non empty (the child we are in and we are going to remove is not the only child) */
7828 break;
7829 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007830 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007831 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007832
Radek Krejci0b7704f2016-03-18 12:16:14 +01007833 /* auto-delete */
7834 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7835 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007836 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007837 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007838 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007839
Radek Krejci0b7704f2016-03-18 12:16:14 +01007840 lyd_unlink(unres->node[i]);
7841 unres->type[i] = UNRES_DELETE;
7842 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007843
7844 /* update the rest of unres items */
7845 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007846 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007847 continue;
7848 }
7849
7850 /* test if the node is in subtree to be deleted */
7851 for (parent = unres->node[j]; parent; parent = parent->parent) {
7852 if (parent == unres->node[i]) {
7853 /* yes, it is */
7854 unres->type[j] = UNRES_RESOLVED;
7855 resolved++;
7856 break;
7857 }
7858 }
7859 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007860 } else {
7861 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007862 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007863 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007864 resolved++;
7865 progress = 1;
7866 } else if (rc == -1) {
7867 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007868 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007869 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007870 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007871 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007872 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007873 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007874 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007875
Radek Krejci0b7704f2016-03-18 12:16:14 +01007876 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007877 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007878 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007879 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007880 return -1;
7881 }
7882
7883 for (i = 0; del_items && i < unres->count; i++) {
7884 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7885 if (unres->type[i] != UNRES_DELETE) {
7886 continue;
7887 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007888 if (!unres->node[i]) {
7889 unres->type[i] = UNRES_RESOLVED;
7890 del_items--;
7891 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007892 }
7893
7894 /* really remove the complete subtree */
7895 lyd_free(unres->node[i]);
7896 unres->type[i] = UNRES_RESOLVED;
7897 del_items--;
7898 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007899 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007900
7901 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007902 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007903 if (unres->type[i] == UNRES_RESOLVED) {
7904 continue;
7905 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007906 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007907
Michal Vasko3cfa3182017-01-17 10:00:58 +01007908 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007909 if (rc) {
7910 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007911 return -1;
7912 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007913
7914 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007915 }
7916
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007917 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007918 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007919 return EXIT_SUCCESS;
7920}