blob: 8373177793a63e97a0997261a74236fadc3dffb6 [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 Vasko9fbb6e82017-07-04 13:50:04 +0200914 * predicate-expr = "." / [prefix:]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.
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200920 * @param[out] mod_name Points to the list key module name.
921 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100922 * @param[out] name Points to the list key name.
923 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100924 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100925 * @param[out] val_len Length of \p value.
926 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
927 */
Michal Vasko22448d32016-03-16 13:17:29 +0100928int
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200929parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
930 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100931{
932 const char *ptr;
933 int parsed = 0, ret;
934 char quote;
935
936 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200937 if (mod_name) {
938 *mod_name = NULL;
939 }
940 if (mod_name_len) {
941 *mod_name_len = 0;
942 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100943 if (name) {
944 *name = NULL;
945 }
946 if (nam_len) {
947 *nam_len = 0;
948 }
949 if (value) {
950 *value = NULL;
951 }
952 if (val_len) {
953 *val_len = 0;
954 }
955 if (has_predicate) {
956 *has_predicate = 0;
957 }
958
959 if (id[0] != '[') {
960 return -parsed;
961 }
962
963 ++parsed;
964 ++id;
965
966 while (isspace(id[0])) {
967 ++parsed;
968 ++id;
969 }
970
Michal Vasko22448d32016-03-16 13:17:29 +0100971 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200972 if (id[0] == '.') {
973 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200974
975 if (name) {
976 *name = id;
977 }
978 if (nam_len) {
979 *nam_len = ret;
980 }
Michal Vasko58c2aab2017-01-05 10:02:05 +0100981 } else if (isdigit(id[0])) {
982 if (id[0] == '0') {
983 return -parsed;
984 }
985 ret = 1;
986 while (isdigit(id[ret])) {
987 ++ret;
988 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200989
990 if (name) {
991 *name = id;
992 }
993 if (nam_len) {
994 *nam_len = ret;
995 }
996 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100997 return -parsed + ret;
998 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100999
1000 parsed += ret;
1001 id += ret;
1002
1003 while (isspace(id[0])) {
1004 ++parsed;
1005 ++id;
1006 }
1007
1008 /* there is value as well */
1009 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001010 if (name && isdigit(**name)) {
1011 return -parsed;
1012 }
1013
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001014 ++parsed;
1015 ++id;
1016
1017 while (isspace(id[0])) {
1018 ++parsed;
1019 ++id;
1020 }
1021
1022 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1023 if ((id[0] == '\"') || (id[0] == '\'')) {
1024 quote = id[0];
1025
1026 ++parsed;
1027 ++id;
1028
1029 if ((ptr = strchr(id, quote)) == NULL) {
1030 return -parsed;
1031 }
1032 ret = ptr - id;
1033
1034 if (value) {
1035 *value = id;
1036 }
1037 if (val_len) {
1038 *val_len = ret;
1039 }
1040
1041 parsed += ret + 1;
1042 id += ret + 1;
1043 } else {
1044 return -parsed;
1045 }
1046
1047 while (isspace(id[0])) {
1048 ++parsed;
1049 ++id;
1050 }
1051 }
1052
1053 if (id[0] != ']') {
1054 return -parsed;
1055 }
1056
1057 ++parsed;
1058 ++id;
1059
1060 if ((id[0] == '[') && has_predicate) {
1061 *has_predicate = 1;
1062 }
1063
1064 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001065}
1066
1067/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001068 * @brief Resolve (find) a feature definition. Logs directly.
1069 *
1070 * @param[in] feat_name Feature name to resolve.
1071 * @param[in] len Length of \p feat_name.
1072 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001073 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1074 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001075 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001076 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001077 */
1078static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001079resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001080{
1081 char *str;
1082 const char *mod_name, *name;
1083 int mod_name_len, nam_len, i, j;
1084 const struct lys_module *module;
1085
Radek Krejci9ff0a922016-07-14 13:08:05 +02001086 assert(feature);
1087
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001088 /* check prefix */
1089 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1090 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1091 return -1;
1092 }
1093
1094 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1095 if (!module) {
1096 /* identity refers unknown data model */
1097 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1098 return -1;
1099 }
1100
Radek Krejci9ff0a922016-07-14 13:08:05 +02001101 if (module != node->module && module == lys_node_module(node)) {
1102 /* first, try to search directly in submodule where the feature was mentioned */
1103 for (j = 0; j < node->module->features_size; j++) {
1104 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1105 /* check status */
1106 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001107 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001108 return -1;
1109 }
1110 *feature = &node->module->features[j];
1111 return 0;
1112 }
1113 }
1114 }
1115
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001116 /* search in the identified module ... */
1117 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001118 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001119 /* check status */
1120 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001121 module->features[j].module, module->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->features[j];
1125 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 }
1127 }
1128 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001129 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001130 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001131 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1132 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001133 /* check status */
1134 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1135 module->inc[i].submodule->features[j].flags,
1136 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001137 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001138 return -1;
1139 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140 *feature = &module->inc[i].submodule->features[j];
1141 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001142 }
1143 }
1144 }
1145
1146 /* not found */
1147 str = strndup(feat_name, len);
1148 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1149 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001150 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151}
1152
Radek Krejci9ff0a922016-07-14 13:08:05 +02001153/*
1154 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001155 * - 1 if enabled
1156 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001157 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001159resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001160{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001161 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001162
Radek Krejci9ff0a922016-07-14 13:08:05 +02001163 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001164 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001165 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001166 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001167 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001168
Radek Krejci69b8d922016-07-27 13:13:41 +02001169 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001170}
1171
1172static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001173resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001174{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001175 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001176 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001177
Radek Krejci9ff0a922016-07-14 13:08:05 +02001178 op = iff_getop(expr->expr, *index_e);
1179 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001180
Radek Krejci9ff0a922016-07-14 13:08:05 +02001181 switch (op) {
1182 case LYS_IFF_F:
1183 /* resolve feature */
1184 return resolve_feature_value(expr->features[(*index_f)++]);
1185 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001186 /* invert result */
1187 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001188 case LYS_IFF_AND:
1189 case LYS_IFF_OR:
1190 a = resolve_iffeature_recursive(expr, index_e, index_f);
1191 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001192 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001193 return a && b;
1194 } else { /* LYS_IFF_OR */
1195 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001196 }
1197 }
1198
Radek Krejciaf566332017-02-07 15:56:59 +01001199 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001200}
1201
1202int
1203resolve_iffeature(struct lys_iffeature *expr)
1204{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001205 int index_e = 0, index_f = 0;
1206
1207 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001208 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001209 }
Radek Krejciaf566332017-02-07 15:56:59 +01001210 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001211}
1212
1213struct iff_stack {
1214 int size;
1215 int index; /* first empty item */
1216 uint8_t *stack;
1217};
1218
1219static int
1220iff_stack_push(struct iff_stack *stack, uint8_t value)
1221{
1222 if (stack->index == stack->size) {
1223 stack->size += 4;
1224 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001225 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM; stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001226 }
1227
1228 stack->stack[stack->index++] = value;
1229 return EXIT_SUCCESS;
1230}
1231
1232static uint8_t
1233iff_stack_pop(struct iff_stack *stack)
1234{
1235 stack->index--;
1236 return stack->stack[stack->index];
1237}
1238
1239static void
1240iff_stack_clean(struct iff_stack *stack)
1241{
1242 stack->size = 0;
1243 free(stack->stack);
1244}
1245
1246static void
1247iff_setop(uint8_t *list, uint8_t op, int pos)
1248{
1249 uint8_t *item;
1250 uint8_t mask = 3;
1251
1252 assert(pos >= 0);
1253 assert(op <= 3); /* max 2 bits */
1254
1255 item = &list[pos / 4];
1256 mask = mask << 2 * (pos % 4);
1257 *item = (*item) & ~mask;
1258 *item = (*item) | (op << 2 * (pos % 4));
1259}
1260
1261uint8_t
1262iff_getop(uint8_t *list, int pos)
1263{
1264 uint8_t *item;
1265 uint8_t mask = 3, result;
1266
1267 assert(pos >= 0);
1268
1269 item = &list[pos / 4];
1270 result = (*item) & (mask << 2 * (pos % 4));
1271 return result >> 2 * (pos % 4);
1272}
1273
1274#define LYS_IFF_LP 0x04 /* ( */
1275#define LYS_IFF_RP 0x08 /* ) */
1276
Radek Krejcicbb473e2016-09-16 14:48:32 +02001277/* internal structure for passing data for UNRES_IFFEAT */
1278struct unres_iffeat_data {
1279 struct lys_node *node;
1280 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001281 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001282};
1283
Radek Krejci9ff0a922016-07-14 13:08:05 +02001284void
1285resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1286{
1287 unsigned int e = 0, f = 0, r = 0;
1288 uint8_t op;
1289
1290 assert(iffeat);
1291
1292 if (!iffeat->expr) {
1293 goto result;
1294 }
1295
1296 do {
1297 op = iff_getop(iffeat->expr, e++);
1298 switch (op) {
1299 case LYS_IFF_NOT:
1300 if (!r) {
1301 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001302 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001303 break;
1304 case LYS_IFF_AND:
1305 case LYS_IFF_OR:
1306 if (!r) {
1307 r += 2;
1308 } else {
1309 r += 1;
1310 }
1311 break;
1312 case LYS_IFF_F:
1313 f++;
1314 if (r) {
1315 r--;
1316 }
1317 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001318 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001319 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001320
Radek Krejci9ff0a922016-07-14 13:08:05 +02001321result:
1322 if (expr_size) {
1323 *expr_size = e;
1324 }
1325 if (feat_size) {
1326 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001327 }
1328}
1329
1330int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001331resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001332 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001333{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001334 const char *c = value;
1335 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001336 int i, j, last_not, checkversion = 0;
1337 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001338 uint8_t op;
1339 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001340 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001341
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 assert(c);
1343
1344 if (isspace(c[0])) {
1345 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1346 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001347 }
1348
Radek Krejci9ff0a922016-07-14 13:08:05 +02001349 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1350 for (i = j = last_not = 0; c[i]; i++) {
1351 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001352 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001353 j++;
1354 continue;
1355 } else if (c[i] == ')') {
1356 j--;
1357 continue;
1358 } else if (isspace(c[i])) {
1359 continue;
1360 }
1361
1362 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1363 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001364 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001365 return EXIT_FAILURE;
1366 } else if (!isspace(c[i + r])) {
1367 /* feature name starting with the not/and/or */
1368 last_not = 0;
1369 f_size++;
1370 } else if (c[i] == 'n') { /* not operation */
1371 if (last_not) {
1372 /* double not */
1373 expr_size = expr_size - 2;
1374 last_not = 0;
1375 } else {
1376 last_not = 1;
1377 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001378 } else { /* and, or */
1379 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001380 /* not a not operation */
1381 last_not = 0;
1382 }
1383 i += r;
1384 } else {
1385 f_size++;
1386 last_not = 0;
1387 }
1388 expr_size++;
1389
1390 while (!isspace(c[i])) {
1391 if (!c[i] || c[i] == ')') {
1392 i--;
1393 break;
1394 }
1395 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001396 }
1397 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001398 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001399 /* not matching count of ( and ) */
1400 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1401 return EXIT_FAILURE;
1402 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001403
Radek Krejci69b8d922016-07-27 13:13:41 +02001404 if (checkversion || expr_size > 1) {
1405 /* check that we have 1.1 module */
1406 if (node->module->version != 2) {
1407 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1408 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1409 return EXIT_FAILURE;
1410 }
1411 }
1412
Radek Krejci9ff0a922016-07-14 13:08:05 +02001413 /* allocate the memory */
1414 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001415 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001416 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001417 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM, error);
1418 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001419 f_size--; expr_size--; /* used as indexes from now */
1420
1421 for (i--; i >= 0; i--) {
1422 if (c[i] == ')') {
1423 /* push it on stack */
1424 iff_stack_push(&stack, LYS_IFF_RP);
1425 continue;
1426 } else if (c[i] == '(') {
1427 /* pop from the stack into result all operators until ) */
1428 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1429 iff_setop(iffeat_expr->expr, op, expr_size--);
1430 }
1431 continue;
1432 } else if (isspace(c[i])) {
1433 continue;
1434 }
1435
1436 /* end operator or operand -> find beginning and get what is it */
1437 j = i + 1;
1438 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1439 i--;
1440 }
1441 i++; /* get back by one step */
1442
1443 if (!strncmp(&c[i], "not ", 4)) {
1444 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1445 /* double not */
1446 iff_stack_pop(&stack);
1447 } else {
1448 /* not has the highest priority, so do not pop from the stack
1449 * as in case of AND and OR */
1450 iff_stack_push(&stack, LYS_IFF_NOT);
1451 }
1452 } else if (!strncmp(&c[i], "and ", 4)) {
1453 /* as for OR - pop from the stack all operators with the same or higher
1454 * priority and store them to the result, then push the AND to the stack */
1455 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1456 op = iff_stack_pop(&stack);
1457 iff_setop(iffeat_expr->expr, op, expr_size--);
1458 }
1459 iff_stack_push(&stack, LYS_IFF_AND);
1460 } else if (!strncmp(&c[i], "or ", 3)) {
1461 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1462 op = iff_stack_pop(&stack);
1463 iff_setop(iffeat_expr->expr, op, expr_size--);
1464 }
1465 iff_stack_push(&stack, LYS_IFF_OR);
1466 } else {
1467 /* feature name, length is j - i */
1468
1469 /* add it to the result */
1470 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1471
1472 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001473 * forward referenced, we have to keep the feature name in auxiliary
1474 * structure passed into unres */
1475 iff_data = malloc(sizeof *iff_data);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001476 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM, error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001477 iff_data->node = node;
1478 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001479 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001480 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1481 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001482 f_size--;
1483
1484 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001485 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001486 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001487 }
1488 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001489 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001490 while (stack.index) {
1491 op = iff_stack_pop(&stack);
1492 iff_setop(iffeat_expr->expr, op, expr_size--);
1493 }
1494
1495 if (++expr_size || ++f_size) {
1496 /* not all expected operators and operands found */
1497 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1498 rc = EXIT_FAILURE;
1499 } else {
1500 rc = EXIT_SUCCESS;
1501 }
1502
1503error:
1504 /* cleanup */
1505 iff_stack_clean(&stack);
1506
1507 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001508}
1509
1510/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001511 * @brief Resolve (find) a data node based on a schema-nodeid.
1512 *
1513 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1514 * module).
1515 *
1516 */
1517struct lyd_node *
1518resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1519{
1520 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001521 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001522 const struct lys_node *schema = NULL;
1523
1524 assert(nodeid && start);
1525
1526 if (nodeid[0] == '/') {
1527 return NULL;
1528 }
1529
1530 str = p = strdup(nodeid);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001531 LY_CHECK_ERR_RETURN(!str, LOGMEM, NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001532
Michal Vasko3edeaf72016-02-11 13:17:43 +01001533 while (p) {
1534 token = p;
1535 p = strchr(p, '/');
1536 if (p) {
1537 *p = '\0';
1538 p++;
1539 }
1540
Radek Krejci5da4eb62016-04-08 14:45:51 +02001541 if (p) {
1542 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001543 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001544 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001545 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001546 result = NULL;
1547 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001548 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001549
Radek Krejci5da4eb62016-04-08 14:45:51 +02001550 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1551 continue;
1552 }
1553 } else {
1554 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001555 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001556 || !schema) {
1557 result = NULL;
1558 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001559 }
1560 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001561 LY_TREE_FOR(result ? result->child : start, iter) {
1562 if (iter->schema == schema) {
1563 /* move in data tree according to returned schema */
1564 result = iter;
1565 break;
1566 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001567 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001568 if (!iter) {
1569 /* instance not found */
1570 result = NULL;
1571 break;
1572 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001573 }
1574 free(str);
1575
1576 return result;
1577}
1578
Radek Krejcibdf92362016-04-08 14:43:34 +02001579/*
1580 * 0 - ok (done)
1581 * 1 - continue
1582 * 2 - break
1583 * -1 - error
1584 */
Radek Krejci1a9c3612017-04-24 14:49:43 +02001585int
Michal Vaskodc300b02017-04-07 14:09:20 +02001586schema_nodeid_siblingcheck(const struct lys_node *sibling, const char *id, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001587 const char *mod_name, int mod_name_len, const struct lys_node **start_parent)
Radek Krejcibdf92362016-04-08 14:43:34 +02001588{
1589 const struct lys_module *prefix_mod;
1590
1591 /* module check */
1592 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1593 if (!prefix_mod) {
1594 return -1;
1595 }
1596 if (prefix_mod != lys_node_module(sibling)) {
1597 return 1;
1598 }
1599
Radek Krejcibdf92362016-04-08 14:43:34 +02001600 /* the result node? */
1601 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001602 return 0;
1603 }
1604
Michal Vaskodc300b02017-04-07 14:09:20 +02001605 /* move down the tree, if possible */
1606 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1607 return -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001608 }
Michal Vaskodc300b02017-04-07 14:09:20 +02001609 *start_parent = sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001610
1611 return 2;
1612}
1613
Radek Krejcidf46e222016-11-08 11:57:37 +01001614/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
Radek Krejcidf46e222016-11-08 11:57:37 +01001615 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001616int
1617resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Michal Vaskobb520442017-05-23 10:55:18 +02001618 const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001619{
Michal Vaskobb520442017-05-23 10:55:18 +02001620 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001621 const struct lys_node *sibling, *start_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02001622 struct lys_node_augment *last_aug;
1623 int r, nam_len, mod_name_len = 0, is_relative = -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001624 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001625 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001626
1627 assert(nodeid && (start || module) && !(start && module) && ret);
1628
1629 id = nodeid;
1630
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001631 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 +01001632 return ((id - nodeid) - r) + 1;
1633 }
1634 id += r;
1635
1636 if ((is_relative && !start) || (!is_relative && !module)) {
1637 return -1;
1638 }
1639
1640 /* descendant-schema-nodeid */
1641 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001642 module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001643 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001644
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645 /* absolute-schema-nodeid */
1646 } else {
1647 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001648 if (!start_mod) {
1649 return -1;
1650 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001651 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001652 }
1653
1654 while (1) {
1655 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001656 last_aug = NULL;
1657
1658 if (start_parent) {
Michal Vaskoe4c83442017-07-11 08:49:01 +02001659 if (mod_name && (strncmp(mod_name, module->name, mod_name_len)
1660 || (mod_name_len != (signed)strlen(module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001661 /* we are getting into another module (augment) */
1662 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1663 if (!aux_mod) {
1664 return -1;
1665 }
1666 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001667 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001668 * because this module may be not implemented and it augments something in another module and
1669 * there is another augment augmenting that previous one */
Michal Vaskoe4c83442017-07-11 08:49:01 +02001670 aux_mod = module;
Michal Vaskobb520442017-05-23 10:55:18 +02001671 }
1672
1673 /* if the module is implemented, all the augments will be connected */
1674 if (!aux_mod->implemented) {
1675get_next_augment:
1676 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1677 }
1678 }
1679
1680 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001681 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001682 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001683 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001684 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001685 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001686 *ret = sibling;
1687 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001688 } else if (r == 1) {
1689 continue;
1690 } else if (r == 2) {
1691 break;
1692 } else {
1693 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001694 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001695 }
1696 }
1697
1698 /* no match */
1699 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001700 if (last_aug) {
1701 /* it still could be in another augment */
1702 goto get_next_augment;
1703 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001704 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001705 return EXIT_SUCCESS;
1706 }
1707
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001708 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 +01001709 return ((id - nodeid) - r) + 1;
1710 }
1711 id += r;
1712 }
1713
1714 /* cannot get here */
1715 LOGINT;
1716 return -1;
1717}
1718
Radek Krejcif3c71de2016-04-11 12:45:46 +02001719/* unique, refine,
1720 * >0 - unexpected char on position (ret - 1),
1721 * 0 - ok (but ret can still be NULL),
1722 * -1 - error,
1723 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001724int
1725resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001726 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001727{
1728 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001729 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001730 int r, nam_len, mod_name_len, is_relative = -1;
1731 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001732 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001733
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001734 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001735 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001736
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001737 if (!start) {
1738 /* leaf not found */
1739 return 0;
1740 }
1741
Michal Vasko3edeaf72016-02-11 13:17:43 +01001742 id = nodeid;
1743 module = start->module;
1744
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001745 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 +01001746 return ((id - nodeid) - r) + 1;
1747 }
1748 id += r;
1749
1750 if (!is_relative) {
1751 return -1;
1752 }
1753
Michal Vasko24476fa2017-03-08 12:33:48 +01001754 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001755 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001756 start_parent = lys_parent(start_parent);
1757 }
1758
Michal Vasko3edeaf72016-02-11 13:17:43 +01001759 while (1) {
1760 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001761 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001762 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763 /* name match */
1764 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001765 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001766 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001767 if (!(sibling->nodetype & ret_nodetype)) {
1768 /* wrong node type, too bad */
1769 continue;
1770 }
1771 *ret = sibling;
1772 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001773 } else if (r == 1) {
1774 continue;
1775 } else if (r == 2) {
1776 break;
1777 } else {
1778 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001780 }
1781 }
1782
1783 /* no match */
1784 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001785 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001786 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001787 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1788 *ret = NULL;
1789 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001790 }
1791
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001792 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 +01001793 return ((id - nodeid) - r) + 1;
1794 }
1795 id += r;
1796 }
1797
1798 /* cannot get here */
1799 LOGINT;
1800 return -1;
1801}
1802
1803/* choice default */
1804int
1805resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1806{
1807 /* cannot actually be a path */
1808 if (strchr(nodeid, '/')) {
1809 return -1;
1810 }
1811
Michal Vaskodc300b02017-04-07 14:09:20 +02001812 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001813}
1814
1815/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1816static int
1817resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1818{
1819 const struct lys_module *module;
1820 const char *mod_prefix, *name;
1821 int i, mod_prefix_len, nam_len;
1822
1823 /* parse the identifier, it must be parsed on one call */
1824 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1825 return -i + 1;
1826 }
1827
1828 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1829 if (!module) {
1830 return -1;
1831 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01001832 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001833 start = module->data;
1834 }
1835
1836 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1837
1838 return EXIT_SUCCESS;
1839}
1840
1841int
1842resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1843 const struct lys_node **ret)
1844{
1845 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001846 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001847 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001848 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001849
1850 assert(nodeid && module && ret);
1851 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1852
1853 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01001854 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001855
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001856 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 +01001857 return ((id - nodeid) - r) + 1;
1858 }
1859 id += r;
1860
1861 if (is_relative) {
1862 return -1;
1863 }
1864
1865 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001866 if (!abs_start_mod) {
1867 return -1;
1868 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001869
1870 while (1) {
1871 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001872 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01001873 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1874 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001875 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskobb520442017-05-23 10:55:18 +02001876 r = schema_nodeid_siblingcheck(sibling, id, module, mod_name, mod_name_len, &start_parent);
Radek Krejcibdf92362016-04-08 14:43:34 +02001877 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001878 if (!(sibling->nodetype & ret_nodetype)) {
1879 /* wrong node type, too bad */
1880 continue;
1881 }
1882 *ret = sibling;
1883 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001884 } else if (r == 1) {
1885 continue;
1886 } else if (r == 2) {
1887 break;
1888 } else {
1889 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001890 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001891 }
1892 }
1893
1894 /* no match */
1895 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001896 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001897 return EXIT_SUCCESS;
1898 }
1899
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001900 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 +01001901 return ((id - nodeid) - r) + 1;
1902 }
1903 id += r;
1904 }
1905
1906 /* cannot get here */
1907 LOGINT;
1908 return -1;
1909}
1910
Michal Vaskoe733d682016-03-14 09:08:27 +01001911static int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001912resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list,
1913 const struct lys_module *cur_module, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001914{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001915 const char *mod_name, *name;
1916 int mod_name_len, nam_len, has_predicate, i;
1917 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01001918
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001919 if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001920 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001921 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001922 return -1;
1923 }
1924
1925 predicate += i;
1926 *parsed += i;
1927
Michal Vasko58c2aab2017-01-05 10:02:05 +01001928 if (!isdigit(name[0])) {
1929 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001930 key = (struct lys_node *)list->keys[i];
1931 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
1932 if (mod_name) {
1933 if (!strncmp(lys_node_module(key)->name, mod_name, mod_name_len) && !lys_node_module(key)->name[mod_name_len]) {
1934 break;
1935 }
1936 } else {
1937 if (!strcmp(lys_node_module(key)->name, cur_module->name)) {
1938 break;
1939 }
1940 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001941 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001942 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001943
Michal Vasko58c2aab2017-01-05 10:02:05 +01001944 if (i == list->keys_size) {
1945 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1946 return -1;
1947 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001948 }
1949
1950 /* more predicates? */
1951 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001952 return resolve_json_schema_list_predicate(predicate, list, cur_module, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001953 }
1954
1955 return 0;
1956}
1957
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001958/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001959const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001960resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001961{
Michal Vasko10728b52016-04-07 14:26:29 +02001962 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001963 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001964 const struct lys_node *sibling, *start_parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02001965 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001966 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001967 const struct lys_module *prefix_mod, *cur_module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001968
Michal Vasko3547c532016-03-14 09:40:50 +01001969 assert(nodeid && (ctx || start));
1970 if (!ctx) {
1971 ctx = start->module->ctx;
1972 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001973
1974 id = nodeid;
1975
Michal Vaskoe733d682016-03-14 09:08:27 +01001976 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001977 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001978 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001979 }
1980 id += r;
1981
1982 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001983 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001984 start_parent = start;
1985 while (start_parent && (start_parent->nodetype == LYS_USES)) {
1986 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01001987 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001988 cur_module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01001989 } else {
1990 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001991 str = strndup(nodeid, (name + nam_len) - nodeid);
1992 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1993 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001994 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001995 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1996 LOGINT;
1997 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001998 }
1999
Michal Vasko971a3ca2016-04-01 13:09:29 +02002000 if (ly_buf_used && module_name[0]) {
2001 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2002 }
2003 ly_buf_used++;
2004
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002005 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002006 module_name[mod_name_len] = '\0';
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002007 cur_module = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002008
2009 if (buf_backup) {
2010 /* return previous internal buffer content */
2011 strcpy(module_name, buf_backup);
2012 free(buf_backup);
2013 buf_backup = NULL;
2014 }
2015 ly_buf_used--;
2016
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002017 if (!cur_module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002018 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2019 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2020 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002021 return NULL;
2022 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002023 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002024
2025 /* now it's as if there was no module name */
2026 mod_name = NULL;
2027 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002028 }
2029
Michal Vasko3edeaf72016-02-11 13:17:43 +01002030 while (1) {
2031 sibling = NULL;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002032 while ((sibling = lys_getnext(sibling, start_parent, cur_module,
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002033 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002034 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002035 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002036 /* module check */
2037 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002038 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002039 LOGINT;
2040 return NULL;
2041 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002042
2043 if (ly_buf_used && module_name[0]) {
2044 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2045 }
2046 ly_buf_used++;
2047
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002048 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002049 module_name[mod_name_len] = '\0';
2050 /* will also find an augment module */
2051 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002052
2053 if (buf_backup) {
2054 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002055 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002056 free(buf_backup);
2057 buf_backup = NULL;
2058 }
2059 ly_buf_used--;
2060
Michal Vasko3edeaf72016-02-11 13:17:43 +01002061 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002062 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2063 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2064 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002065 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002066 }
2067 } else {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002068 prefix_mod = cur_module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002069 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002070 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002071 continue;
2072 }
2073
Michal Vaskoe733d682016-03-14 09:08:27 +01002074 /* do we have some predicates on it? */
2075 if (has_predicate) {
2076 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002077 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002078 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002079 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2080 return NULL;
2081 }
2082 } else if (sibling->nodetype == LYS_LIST) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002083 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, cur_module, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002084 return NULL;
2085 }
2086 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002087 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002088 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002089 }
2090 id += r;
2091 }
2092
Michal Vasko3edeaf72016-02-11 13:17:43 +01002093 /* the result node? */
2094 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002095 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002096 }
2097
Michal Vaskodc300b02017-04-07 14:09:20 +02002098 /* move down the tree, if possible */
2099 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2100 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2101 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002102 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002103 start_parent = sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002104 break;
2105 }
2106 }
2107
2108 /* no match */
2109 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002110 str = strndup(nodeid, (name + nam_len) - nodeid);
2111 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2112 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002113 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002114 }
2115
Michal Vaskoe733d682016-03-14 09:08:27 +01002116 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 +01002117 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002118 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002119 }
2120 id += r;
2121 }
2122
2123 /* cannot get here */
2124 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002125 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002126}
2127
Michal Vasko22448d32016-03-16 13:17:29 +01002128static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002129resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002130 int position, const struct lys_module *cur_module, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002131{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002132 const char *mod_name, *name, *value, *key_val;
2133 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002134 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002135 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002136
Radek Krejci61a86c62016-03-24 11:06:44 +01002137 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002138 assert(node->schema->nodetype == LYS_LIST);
2139
Michal Vasko53adfc72017-01-06 10:39:10 +01002140 /* is the predicate a number? */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002141 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko53adfc72017-01-06 10:39:10 +01002142 || !strncmp(name, ".", nam_len)) {
2143 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2144 return -1;
2145 }
2146
2147 if (isdigit(name[0])) {
2148 if (position == atoi(name)) {
2149 /* match */
2150 *parsed += r;
2151 return 0;
2152 } else {
2153 /* not a match */
2154 return 1;
2155 }
2156 }
2157
2158 if (!((struct lys_node_list *)node->schema)->keys_size) {
2159 /* no keys in schema - causes an error later */
2160 return 0;
2161 }
2162
Michal Vaskof29903d2016-04-18 13:13:10 +02002163 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002164 if (!key) {
2165 /* it is not a position, so we need a key for it to be a match */
2166 return 1;
2167 }
2168
2169 /* go through all the keys */
2170 i = 0;
2171 goto check_parsed_values;
2172
2173 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002174 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002175 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002176 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002177 }
2178
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002179 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002180 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002181 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002182 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002183 }
2184
Michal Vasko53adfc72017-01-06 10:39:10 +01002185check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002186 predicate += r;
2187 *parsed += r;
2188
Michal Vaskof29903d2016-04-18 13:13:10 +02002189 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002190 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002191 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002192 }
2193
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002194 if (mod_name) {
2195 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2196 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
2197 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2198 return -1;
2199 }
2200 } else {
2201 if (strcmp(lyd_node_module((struct lyd_node *)key)->name, cur_module->name)) {
2202 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2203 return -1;
2204 }
2205 }
2206
Michal Vasko9ba34de2016-12-07 12:21:19 +01002207 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002208 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002209 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2210 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002211 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2212 } else {
2213 key_val = key->value_str;
2214 }
2215
Michal Vasko22448d32016-03-16 13:17:29 +01002216 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002217 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002218 return 1;
2219 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002220
2221 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002222 }
2223
2224 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002225 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002226 return -1;
2227 }
2228
2229 return 0;
2230}
2231
Radek Krejci45826012016-08-24 15:07:57 +02002232/**
2233 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2234 *
2235 * @param[in] nodeid Node data path to find
2236 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2237 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2238 * @param[out] parsed Number of characters processed in \p id
2239 * @return The closes parent (or the node itself) from the path
2240 */
Michal Vasko22448d32016-03-16 13:17:29 +01002241struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002242resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2243 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002244{
Michal Vasko10728b52016-04-07 14:26:29 +02002245 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002246 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002247 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002248 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002249 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002250 struct lyd_node_leaf_list *llist;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002251 const struct lys_module *prefix_mod, *cur_module;
Michal Vasko22448d32016-03-16 13:17:29 +01002252 struct ly_ctx *ctx;
2253
2254 assert(nodeid && start && parsed);
2255
2256 ctx = start->schema->module->ctx;
2257 id = nodeid;
2258
2259 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 +01002260 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002261 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002262 return NULL;
2263 }
2264 id += r;
2265 /* add it to parsed only after the data node was actually found */
2266 last_parsed = r;
2267
2268 if (is_relative) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002269 cur_module = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002270 start = start->child;
2271 } else {
2272 for (; start->parent; start = start->parent);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002273 cur_module = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002274 }
2275
2276 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002277 list_instance_position = 0;
2278
Michal Vasko22448d32016-03-16 13:17:29 +01002279 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002280 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002281 if (lys_parent(sibling->schema)) {
2282 if (options & LYD_PATH_OPT_OUTPUT) {
2283 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002284 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002285 *parsed = -1;
2286 return NULL;
2287 }
2288 } else {
2289 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002290 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002291 *parsed = -1;
2292 return NULL;
2293 }
2294 }
2295 }
2296
Michal Vasko22448d32016-03-16 13:17:29 +01002297 /* name match */
2298 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2299
2300 /* module check */
2301 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002302 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002303 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002304 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002305 return NULL;
2306 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002307
2308 if (ly_buf_used && module_name[0]) {
2309 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2310 }
2311 ly_buf_used++;
2312
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002313 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002314 module_name[mod_name_len] = '\0';
2315 /* will also find an augment module */
2316 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002317
2318 if (buf_backup) {
2319 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002320 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002321 free(buf_backup);
2322 buf_backup = NULL;
2323 }
2324 ly_buf_used--;
2325
Michal Vasko22448d32016-03-16 13:17:29 +01002326 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002327 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2328 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2329 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002330 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002331 return NULL;
2332 }
2333 } else {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002334 prefix_mod = cur_module;
Michal Vasko22448d32016-03-16 13:17:29 +01002335 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002336 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002337 continue;
2338 }
2339
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002340 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002341 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002342 llist = (struct lyd_node_leaf_list *)sibling;
2343
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002344 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002345 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002346 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2347 &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002348 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2349 *parsed = -1;
2350 return NULL;
2351 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002352 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2353 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2354 *parsed = -1;
2355 return NULL;
2356 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002357 } else {
2358 r = 0;
2359 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002360 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002361 }
2362 }
2363
Michal Vasko9ba34de2016-12-07 12:21:19 +01002364 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002365 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002366 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2367 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002368 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2369 } else {
2370 data_val = llist->value_str;
2371 }
2372
2373 if ((!llist_value && data_val && data_val[0])
2374 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002375 continue;
2376 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002377
Michal Vaskof0a50972016-10-19 11:33:55 +02002378 id += r;
2379 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002380 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002381
Radek Krejci45826012016-08-24 15:07:57 +02002382 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002383 /* 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 +01002384 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002385 /* none match */
2386 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002387 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002388
2389 ++list_instance_position;
2390 r = 0;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002391 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, cur_module, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002392 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002393 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002394 return NULL;
2395 } else if (ret == 1) {
2396 /* this list instance does not match */
2397 continue;
2398 }
2399 id += r;
2400 last_parsed += r;
2401 }
2402
2403 *parsed += last_parsed;
2404
2405 /* the result node? */
2406 if (!id[0]) {
2407 return sibling;
2408 }
2409
2410 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002411 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002412 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002413 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002414 return NULL;
2415 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002416 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002417 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002418 break;
2419 }
2420 }
2421
2422 /* no match, return last match */
2423 if (!sibling) {
2424 return last_match;
2425 }
2426
2427 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 +01002428 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002429 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002430 return NULL;
2431 }
2432 id += r;
2433 last_parsed = r;
2434 }
2435
2436 /* cannot get here */
2437 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002438 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002439 return NULL;
2440}
2441
Michal Vasko3edeaf72016-02-11 13:17:43 +01002442/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002443 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002444 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002445 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002446 * @param[in] str_restr Restriction as a string.
2447 * @param[in] type Type of the restriction.
2448 * @param[out] ret Final interval structure that starts with
2449 * the interval of the initial type, continues with intervals
2450 * of any superior types derived from the initial one, and
2451 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002452 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002453 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002454 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002455int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002456resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002457{
2458 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002459 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002460 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002461 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002462 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002463 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002464 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002465
2466 switch (type->base) {
2467 case LY_TYPE_BINARY:
2468 kind = 0;
2469 local_umin = 0;
2470 local_umax = 18446744073709551615UL;
2471
2472 if (!str_restr && type->info.binary.length) {
2473 str_restr = type->info.binary.length->expr;
2474 }
2475 break;
2476 case LY_TYPE_DEC64:
2477 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002478 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2479 local_fmax = __INT64_C(9223372036854775807);
2480 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002481
2482 if (!str_restr && type->info.dec64.range) {
2483 str_restr = type->info.dec64.range->expr;
2484 }
2485 break;
2486 case LY_TYPE_INT8:
2487 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002488 local_smin = __INT64_C(-128);
2489 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002490
2491 if (!str_restr && type->info.num.range) {
2492 str_restr = type->info.num.range->expr;
2493 }
2494 break;
2495 case LY_TYPE_INT16:
2496 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002497 local_smin = __INT64_C(-32768);
2498 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002499
2500 if (!str_restr && type->info.num.range) {
2501 str_restr = type->info.num.range->expr;
2502 }
2503 break;
2504 case LY_TYPE_INT32:
2505 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002506 local_smin = __INT64_C(-2147483648);
2507 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002508
2509 if (!str_restr && type->info.num.range) {
2510 str_restr = type->info.num.range->expr;
2511 }
2512 break;
2513 case LY_TYPE_INT64:
2514 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002515 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2516 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002517
2518 if (!str_restr && type->info.num.range) {
2519 str_restr = type->info.num.range->expr;
2520 }
2521 break;
2522 case LY_TYPE_UINT8:
2523 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002524 local_umin = __UINT64_C(0);
2525 local_umax = __UINT64_C(255);
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_UINT16:
2532 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002533 local_umin = __UINT64_C(0);
2534 local_umax = __UINT64_C(65535);
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_UINT32:
2541 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002542 local_umin = __UINT64_C(0);
2543 local_umax = __UINT64_C(4294967295);
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_UINT64:
2550 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002551 local_umin = __UINT64_C(0);
2552 local_umax = __UINT64_C(18446744073709551615);
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_STRING:
2559 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002560 local_umin = __UINT64_C(0);
2561 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002562
2563 if (!str_restr && type->info.str.length) {
2564 str_restr = type->info.str.length->expr;
2565 }
2566 break;
2567 default:
2568 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002569 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570 }
2571
2572 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002573 if (type->der) {
2574 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002575 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002576 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002577 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002578 assert(!intv || (intv->kind == kind));
2579 }
2580
2581 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002582 /* we do not have any restriction, return superior ones */
2583 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002584 return EXIT_SUCCESS;
2585 }
2586
2587 /* adjust local min and max */
2588 if (intv) {
2589 tmp_intv = intv;
2590
2591 if (kind == 0) {
2592 local_umin = tmp_intv->value.uval.min;
2593 } else if (kind == 1) {
2594 local_smin = tmp_intv->value.sval.min;
2595 } else if (kind == 2) {
2596 local_fmin = tmp_intv->value.fval.min;
2597 }
2598
2599 while (tmp_intv->next) {
2600 tmp_intv = tmp_intv->next;
2601 }
2602
2603 if (kind == 0) {
2604 local_umax = tmp_intv->value.uval.max;
2605 } else if (kind == 1) {
2606 local_smax = tmp_intv->value.sval.max;
2607 } else if (kind == 2) {
2608 local_fmax = tmp_intv->value.fval.max;
2609 }
2610 }
2611
2612 /* finally parse our restriction */
2613 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002614 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002615 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002616 if (!tmp_local_intv) {
2617 assert(!local_intv);
2618 local_intv = malloc(sizeof *local_intv);
2619 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002620 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002621 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002622 tmp_local_intv = tmp_local_intv->next;
2623 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02002624 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM, error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625
2626 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002627 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002628 tmp_local_intv->next = NULL;
2629
2630 /* min */
2631 ptr = seg_ptr;
2632 while (isspace(ptr[0])) {
2633 ++ptr;
2634 }
2635 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2636 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002637 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002638 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002639 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002640 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002641 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2642 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2643 goto error;
2644 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002645 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002646 } else if (!strncmp(ptr, "min", 3)) {
2647 if (kind == 0) {
2648 tmp_local_intv->value.uval.min = local_umin;
2649 } else if (kind == 1) {
2650 tmp_local_intv->value.sval.min = local_smin;
2651 } else if (kind == 2) {
2652 tmp_local_intv->value.fval.min = local_fmin;
2653 }
2654
2655 ptr += 3;
2656 } else if (!strncmp(ptr, "max", 3)) {
2657 if (kind == 0) {
2658 tmp_local_intv->value.uval.min = local_umax;
2659 } else if (kind == 1) {
2660 tmp_local_intv->value.sval.min = local_smax;
2661 } else if (kind == 2) {
2662 tmp_local_intv->value.fval.min = local_fmax;
2663 }
2664
2665 ptr += 3;
2666 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002667 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002668 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002669 }
2670
2671 while (isspace(ptr[0])) {
2672 ptr++;
2673 }
2674
2675 /* no interval or interval */
2676 if ((ptr[0] == '|') || !ptr[0]) {
2677 if (kind == 0) {
2678 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2679 } else if (kind == 1) {
2680 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2681 } else if (kind == 2) {
2682 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2683 }
2684 } else if (!strncmp(ptr, "..", 2)) {
2685 /* skip ".." */
2686 ptr += 2;
2687 while (isspace(ptr[0])) {
2688 ++ptr;
2689 }
2690
2691 /* max */
2692 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2693 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002694 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002695 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002696 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002697 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002698 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2699 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2700 goto error;
2701 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002702 }
2703 } else if (!strncmp(ptr, "max", 3)) {
2704 if (kind == 0) {
2705 tmp_local_intv->value.uval.max = local_umax;
2706 } else if (kind == 1) {
2707 tmp_local_intv->value.sval.max = local_smax;
2708 } else if (kind == 2) {
2709 tmp_local_intv->value.fval.max = local_fmax;
2710 }
2711 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002712 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002713 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002714 }
2715 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002716 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002717 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002718 }
2719
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002720 /* check min and max in correct order*/
2721 if (kind == 0) {
2722 /* current segment */
2723 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2724 goto error;
2725 }
2726 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2727 goto error;
2728 }
2729 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002730 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002731 goto error;
2732 }
2733 } else if (kind == 1) {
2734 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2735 goto error;
2736 }
2737 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2738 goto error;
2739 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002740 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002741 goto error;
2742 }
2743 } else if (kind == 2) {
2744 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2745 goto error;
2746 }
2747 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2748 goto error;
2749 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002750 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002751 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002752 goto error;
2753 }
2754 }
2755
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002756 /* next segment (next OR) */
2757 seg_ptr = strchr(seg_ptr, '|');
2758 if (!seg_ptr) {
2759 break;
2760 }
2761 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002762 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002763 }
2764
2765 /* check local restrictions against superior ones */
2766 if (intv) {
2767 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002768 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002769
2770 while (tmp_local_intv && tmp_intv) {
2771 /* reuse local variables */
2772 if (kind == 0) {
2773 local_umin = tmp_local_intv->value.uval.min;
2774 local_umax = tmp_local_intv->value.uval.max;
2775
2776 /* it must be in this interval */
2777 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2778 /* this interval is covered, next one */
2779 if (local_umax <= tmp_intv->value.uval.max) {
2780 tmp_local_intv = tmp_local_intv->next;
2781 continue;
2782 /* ascending order of restrictions -> fail */
2783 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002784 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002785 }
2786 }
2787 } else if (kind == 1) {
2788 local_smin = tmp_local_intv->value.sval.min;
2789 local_smax = tmp_local_intv->value.sval.max;
2790
2791 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2792 if (local_smax <= tmp_intv->value.sval.max) {
2793 tmp_local_intv = tmp_local_intv->next;
2794 continue;
2795 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002796 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002797 }
2798 }
2799 } else if (kind == 2) {
2800 local_fmin = tmp_local_intv->value.fval.min;
2801 local_fmax = tmp_local_intv->value.fval.max;
2802
Michal Vasko4d1f0482016-09-19 14:35:06 +02002803 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002804 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002805 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002806 tmp_local_intv = tmp_local_intv->next;
2807 continue;
2808 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002809 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002810 }
2811 }
2812 }
2813
2814 tmp_intv = tmp_intv->next;
2815 }
2816
2817 /* some interval left uncovered -> fail */
2818 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002819 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002820 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002821 }
2822
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 /* append the local intervals to all the intervals of the superior types, return it all */
2824 if (intv) {
2825 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2826 tmp_intv->next = local_intv;
2827 } else {
2828 intv = local_intv;
2829 }
2830 *ret = intv;
2831
2832 return EXIT_SUCCESS;
2833
2834error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835 while (intv) {
2836 tmp_intv = intv->next;
2837 free(intv);
2838 intv = tmp_intv;
2839 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002840 while (local_intv) {
2841 tmp_local_intv = local_intv->next;
2842 free(local_intv);
2843 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002844 }
2845
Michal Vaskoaeb51802016-04-11 10:58:47 +02002846 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002847}
2848
Michal Vasko730dfdf2015-08-11 14:48:05 +02002849/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002850 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2851 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002852 *
2853 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002854 * @param[in] mod_name Typedef name module name.
2855 * @param[in] module Main module.
2856 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002857 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002858 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002859 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002860 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002861int
Michal Vasko1e62a092015-12-01 12:27:20 +01002862resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2863 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002864{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002865 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002866 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002867 int tpdf_size;
2868
Michal Vasko1dca6882015-10-22 14:29:42 +02002869 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002870 /* no prefix, try built-in types */
2871 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002872 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002873 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01002874 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002875 }
2876 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002877 }
2878 }
2879 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002880 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002881 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002882 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002883 }
2884 }
2885
Michal Vasko1dca6882015-10-22 14:29:42 +02002886 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002887 /* search in local typedefs */
2888 while (parent) {
2889 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002890 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002891 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2892 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002893 break;
2894
Radek Krejci76512572015-08-04 09:47:08 +02002895 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002896 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2897 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002898 break;
2899
Radek Krejci76512572015-08-04 09:47:08 +02002900 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002901 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2902 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002903 break;
2904
Radek Krejci76512572015-08-04 09:47:08 +02002905 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002906 case LYS_ACTION:
2907 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2908 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002909 break;
2910
Radek Krejci76512572015-08-04 09:47:08 +02002911 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002912 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2913 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002914 break;
2915
Radek Krejci76512572015-08-04 09:47:08 +02002916 case LYS_INPUT:
2917 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002918 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2919 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002920 break;
2921
2922 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002923 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002924 continue;
2925 }
2926
2927 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002928 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002929 match = &tpdf[i];
2930 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002931 }
2932 }
2933
Michal Vaskodcf98e62016-05-05 17:53:53 +02002934 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002935 }
Radek Krejcic071c542016-01-27 14:57:51 +01002936 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002937 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002938 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002939 if (!module) {
2940 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002941 }
2942 }
2943
2944 /* search in top level typedefs */
2945 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002946 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002947 match = &module->tpdf[i];
2948 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002949 }
2950 }
2951
2952 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002953 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002954 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002955 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 +02002956 match = &module->inc[i].submodule->tpdf[j];
2957 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002958 }
2959 }
2960 }
2961
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002962 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002963
2964check_leafref:
2965 if (ret) {
2966 *ret = match;
2967 }
2968 if (match->type.base == LY_TYPE_LEAFREF) {
2969 while (!match->type.info.lref.path) {
2970 match = match->type.der;
2971 assert(match);
2972 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002973 }
2974 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002975}
2976
Michal Vasko1dca6882015-10-22 14:29:42 +02002977/**
2978 * @brief Check the default \p value of the \p type. Logs directly.
2979 *
2980 * @param[in] type Type definition to use.
2981 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002982 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002983 *
2984 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2985 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002986static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01002987check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988{
Radek Krejcibad2f172016-08-02 11:04:15 +02002989 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002990 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01002991 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02002992 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01002993 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002994
Radek Krejci51673202016-11-01 17:00:32 +01002995 assert(value);
2996
Radek Krejcic13db382016-08-16 10:52:42 +02002997 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002998 /* the type was not resolved yet, nothing to do for now */
2999 return EXIT_FAILURE;
Radek Krejci9e6af732017-04-27 14:40:25 +02003000 } else if (!tpdf && !lys_main_module(module)->implemented) {
3001 /* do not check defaults in not implemented module's data */
3002 return EXIT_SUCCESS;
3003 } else if (tpdf && !lys_main_module(module)->implemented && type->base == LY_TYPE_IDENT) {
3004 /* identityrefs are checked when instantiated in data instead of typedef,
3005 * but in typedef the value has to be modified to include the prefix */
3006 if (*value) {
3007 if (strchr(*value, ':')) {
3008 dflt = transform_schema2json(module, *value);
3009 } else {
3010 /* default prefix of the module where the typedef is defined */
3011 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
3012 dflt = lydict_insert_zc(module->ctx, s);
3013 }
3014 lydict_remove(module->ctx, *value);
3015 *value = dflt;
3016 }
3017 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003018 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3019 /* leafref in typedef cannot be checked */
3020 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003021 }
3022
Radek Krejci51673202016-11-01 17:00:32 +01003023 dflt = *value;
3024 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003025 /* we do not have a new default value, so is there any to check even, in some base type? */
3026 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3027 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003028 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003029 break;
3030 }
3031 }
3032
Radek Krejci51673202016-11-01 17:00:32 +01003033 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003034 /* no default value, nothing to check, all is well */
3035 return EXIT_SUCCESS;
3036 }
3037
3038 /* 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)? */
3039 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003040 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003041 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3042 return EXIT_SUCCESS;
3043 } else {
3044 /* check the default value from typedef, but use also the typedef's module
3045 * due to possible searching in imported modules which is expected in
3046 * typedef's module instead of module where the typedef is used */
3047 module = base_tpdf->module;
3048 }
3049 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003050 case LY_TYPE_INST:
3051 case LY_TYPE_LEAFREF:
3052 case LY_TYPE_BOOL:
3053 case LY_TYPE_EMPTY:
3054 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3055 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003056 case LY_TYPE_BITS:
3057 /* the default value must match the restricted list of values, if the type was restricted */
3058 if (type->info.bits.count) {
3059 break;
3060 }
3061 return EXIT_SUCCESS;
3062 case LY_TYPE_ENUM:
3063 /* the default value must match the restricted list of values, if the type was restricted */
3064 if (type->info.enums.count) {
3065 break;
3066 }
3067 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003068 case LY_TYPE_DEC64:
3069 if (type->info.dec64.range) {
3070 break;
3071 }
3072 return EXIT_SUCCESS;
3073 case LY_TYPE_BINARY:
3074 if (type->info.binary.length) {
3075 break;
3076 }
3077 return EXIT_SUCCESS;
3078 case LY_TYPE_INT8:
3079 case LY_TYPE_INT16:
3080 case LY_TYPE_INT32:
3081 case LY_TYPE_INT64:
3082 case LY_TYPE_UINT8:
3083 case LY_TYPE_UINT16:
3084 case LY_TYPE_UINT32:
3085 case LY_TYPE_UINT64:
3086 if (type->info.num.range) {
3087 break;
3088 }
3089 return EXIT_SUCCESS;
3090 case LY_TYPE_STRING:
3091 if (type->info.str.length || type->info.str.patterns) {
3092 break;
3093 }
3094 return EXIT_SUCCESS;
3095 case LY_TYPE_UNION:
3096 /* way too much trouble learning whether we need to check the default again, so just do it */
3097 break;
3098 default:
3099 LOGINT;
3100 return -1;
3101 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003102 } else if (type->base == LY_TYPE_EMPTY) {
3103 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3104 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3105 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003106 }
3107
Michal Vasko1dca6882015-10-22 14:29:42 +02003108 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003109 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003110 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003111 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003112 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Radek Krejciaa1303c2017-05-31 13:57:37 +02003113 LY_CHECK_ERR_RETURN(!node.schema, LOGMEM, -1);
Radek Krejcibad2f172016-08-02 11:04:15 +02003114 node.schema->name = strdup("fake-default");
Radek Krejciaa1303c2017-05-31 13:57:37 +02003115 LY_CHECK_ERR_RETURN(!node.schema->name, LOGMEM; free(node.schema), -1);
Michal Vasko56826402016-03-02 11:11:37 +01003116 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003117 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003118
Radek Krejci37b756f2016-01-18 10:15:03 +01003119 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003120 if (!type->info.lref.target) {
3121 ret = EXIT_FAILURE;
3122 goto finish;
3123 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003124 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003125 if (!ret) {
3126 /* adopt possibly changed default value to its canonical form */
3127 if (*value) {
3128 *value = dflt;
3129 }
3130 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003131 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003132 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, NULL, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003133 /* possible forward reference */
3134 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003135 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003136 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003137 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3138 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3139 /* we have refined bits/enums */
3140 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3141 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003142 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003143 }
3144 }
Radek Krejci51673202016-11-01 17:00:32 +01003145 } else {
3146 /* success - adopt canonical form from the node into the default value */
3147 if (dflt != node.value_str) {
3148 /* this can happen only if we have non-inherited default value,
3149 * inherited default values are already in canonical form */
3150 assert(dflt == *value);
3151 *value = node.value_str;
3152 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003153 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003154 }
3155
3156finish:
3157 if (node.value_type == LY_TYPE_BITS) {
3158 free(node.value.bit);
3159 }
3160 free((char *)node.schema->name);
3161 free(node.schema);
3162
3163 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003164}
3165
Michal Vasko730dfdf2015-08-11 14:48:05 +02003166/**
3167 * @brief Check a key for mandatory attributes. Logs directly.
3168 *
3169 * @param[in] key The key to check.
3170 * @param[in] flags What flags to check.
3171 * @param[in] list The list of all the keys.
3172 * @param[in] index Index of the key in the key list.
3173 * @param[in] name The name of the keys.
3174 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003175 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003176 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003177 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003178static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003179check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003180{
Radek Krejciadb57612016-02-16 13:34:34 +01003181 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182 char *dup = NULL;
3183 int j;
3184
3185 /* existence */
3186 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003187 if (name[len] != '\0') {
3188 dup = strdup(name);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003189 LY_CHECK_ERR_RETURN(!dup, LOGMEM, -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003190 dup[len] = '\0';
3191 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003192 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003193 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003194 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003195 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003196 }
3197
3198 /* uniqueness */
3199 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003200 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003201 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003202 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
3204 }
3205
3206 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003207 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003208 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003209 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003210 }
3211
3212 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003213 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003214 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003215 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003216 }
3217
3218 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003219 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003220 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003221 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003222 }
3223
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003224 /* key is not placed from augment */
3225 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003226 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003227 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003228 return -1;
3229 }
3230
Radek Krejci3f21ada2016-08-01 13:34:31 +02003231 /* key is not when/if-feature -conditional */
3232 j = 0;
3233 if (key->when || (key->iffeature_size && (j = 1))) {
3234 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003235 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003236 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003237 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003238 }
3239
Michal Vasko0b85aa82016-03-07 14:37:43 +01003240 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003241}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003242
3243/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003244 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003245 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003246 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003247 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 *
3249 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3250 */
3251int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003252resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003253{
Radek Krejci581ce772015-11-10 17:22:40 +01003254 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003255 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256
Michal Vaskodc300b02017-04-07 14:09:20 +02003257 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003258 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003259 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003260 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003261 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003262 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003263 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003264 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003265 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003266 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003267 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003268 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003269 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003270 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003271 }
Radek Krejci581ce772015-11-10 17:22:40 +01003272 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003273 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003274 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003275 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003276 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003277 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003278 }
3279
Radek Krejcicf509982015-12-15 09:22:44 +01003280 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003281 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3282 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003283 return -1;
3284 }
3285
Radek Krejcid09d1a52016-08-11 14:05:45 +02003286 /* check that all unique's targets are of the same config type */
3287 if (*trg_type) {
3288 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3289 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003290 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003291 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3292 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3293 return -1;
3294 }
3295 } else {
3296 /* first unique */
3297 if (leaf->flags & LYS_CONFIG_W) {
3298 *trg_type = 1;
3299 } else {
3300 *trg_type = 2;
3301 }
3302 }
3303
Radek Krejcica7efb72016-01-18 13:06:01 +01003304 /* set leaf's unique flag */
3305 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3306
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003307 return EXIT_SUCCESS;
3308
3309error:
3310
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003311 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003312}
3313
Radek Krejci0c0086a2016-03-24 15:20:28 +01003314void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003315unres_data_del(struct unres_data *unres, uint32_t i)
3316{
3317 /* there are items after the one deleted */
3318 if (i+1 < unres->count) {
3319 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003320 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003321
3322 /* deleting the last item */
3323 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003324 free(unres->node);
3325 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003326 }
3327
3328 /* if there are no items after and it is not the last one, just move the counter */
3329 --unres->count;
3330}
3331
Michal Vasko0491ab32015-08-19 14:28:29 +02003332/**
3333 * @brief Resolve (find) a data node from a specific module. Does not log.
3334 *
3335 * @param[in] mod Module to search in.
3336 * @param[in] name Name of the data node.
3337 * @param[in] nam_len Length of the name.
3338 * @param[in] start Data node to start the search from.
3339 * @param[in,out] parents Resolved nodes. If there are some parents,
3340 * they are replaced (!!) with the resolvents.
3341 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003342 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003343 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003344static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003345resolve_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 +02003346{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003347 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003348 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003349 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003350
Michal Vasko23b61ec2015-08-19 11:19:50 +02003351 if (!parents->count) {
3352 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003353 parents->node = malloc(sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003354 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003355 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003357 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003358 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003359 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003360 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003361 continue;
3362 }
3363 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003364 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003365 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003366 && node->schema->name[nam_len] == '\0') {
3367 /* matching target */
3368 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003369 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003370 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371 flag = 1;
3372 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003373 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003374 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003375 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003376 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003377 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 }
3380 }
3381 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003382
3383 if (!flag) {
3384 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003385 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003386 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003387 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003388 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 }
3390
Michal Vasko0491ab32015-08-19 14:28:29 +02003391 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003392}
3393
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003394/**
3395 * @brief Resolve (find) a data node. Does not log.
3396 *
Radek Krejci581ce772015-11-10 17:22:40 +01003397 * @param[in] mod_name Module name of the data node.
3398 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003399 * @param[in] name Name of the data node.
3400 * @param[in] nam_len Length of the name.
3401 * @param[in] start Data node to start the search from.
3402 * @param[in,out] parents Resolved nodes. If there are some parents,
3403 * they are replaced (!!) with the resolvents.
3404 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003405 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003406 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003407static int
Radek Krejci581ce772015-11-10 17:22:40 +01003408resolve_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 +02003409 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003410{
Michal Vasko1e62a092015-12-01 12:27:20 +01003411 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003412 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003413
Michal Vasko23b61ec2015-08-19 11:19:50 +02003414 assert(start);
3415
Michal Vasko31fc3672015-10-21 12:08:13 +02003416 if (mod_name) {
3417 /* we have mod_name, find appropriate module */
3418 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003419 if (!str) {
3420 LOGMEM;
3421 return -1;
3422 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003423 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3424 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003425 if (!mod) {
3426 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003427 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003428 }
3429 } else {
3430 /* no prefix, module is the same as of current node */
Michal Vasko39608352017-05-11 10:37:10 +02003431 mod = lyd_node_module(start);
Radek Krejcic5090c32015-08-12 09:46:19 +02003432 }
3433
3434 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003435}
3436
Michal Vasko730dfdf2015-08-11 14:48:05 +02003437/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003438 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003439 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003440 *
Michal Vaskobb211122015-08-19 14:03:11 +02003441 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003442 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003443 * @param[in,out] node_match Nodes satisfying the restriction
3444 * without the predicate. Nodes not
3445 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003446 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003447 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003448 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003449 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003451resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003452 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003454 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003455 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003456 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003457 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3458 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003459 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003460 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003461
3462 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003463 source_match.node = malloc(sizeof *source_match.node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003464 LY_CHECK_ERR_RETURN(!source_match.node, LOGMEM, -1);
3465
Michal Vasko23b61ec2015-08-19 11:19:50 +02003466 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003467 dest_match.node = malloc(sizeof *dest_match.node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003468 LY_CHECK_ERR_RETURN(!dest_match.node, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003469
3470 do {
3471 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3472 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003473 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003474 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003475 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003477 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478 pred += i;
3479
Michal Vasko23b61ec2015-08-19 11:19:50 +02003480 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003481 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003482 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003483
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003484 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003485 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003486 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003487 i = 0;
3488 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003489 }
3490
3491 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003492 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003493 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003494 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3495 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003496 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003497 rc = -1;
3498 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003499 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003500 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003501 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003502 dest_match.node[0] = dest_match.node[0]->parent;
3503 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003504 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003505 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003506 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003507 }
3508 }
3509 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003510 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003511 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003512 i = 0;
3513 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 }
3515
3516 if (pke_len == pke_parsed) {
3517 break;
3518 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003519 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 +02003520 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003521 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003522 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003523 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524 }
3525 pke_parsed += i;
3526 }
3527
3528 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003529 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003530 while (leaf_dst && leaf_dst->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003531 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3532 }
3533 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
Radek Krejci981a8ee2017-03-17 16:48:26 +01003534 while (leaf_src && leaf_src->value_type == LY_TYPE_LEAFREF) {
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003535 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3536 }
Radek Krejci981a8ee2017-03-17 16:48:26 +01003537 if (!leaf_src || !leaf_dst) {
3538 /* not yet resolved leafrefs */
3539 return EXIT_FAILURE;
3540 }
Radek Krejcic7408e72017-03-17 10:43:51 +01003541 if ((leaf_src->value_type & LY_DATA_TYPE_MASK) != (leaf_dst->value_type & LY_DATA_TYPE_MASK)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542 goto remove_leafref;
3543 }
3544
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003545 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003546 goto remove_leafref;
3547 }
3548
3549 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003550 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003551 continue;
3552
3553remove_leafref:
3554 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003555 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003556 }
3557 } while (has_predicate);
3558
Michal Vaskocf024702015-10-08 15:01:42 +02003559 free(source_match.node);
3560 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003561 if (parsed) {
3562 *parsed = parsed_loc;
3563 }
3564 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003565
3566error:
3567
3568 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003569 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003570 }
3571 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003572 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003573 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003574 if (parsed) {
3575 *parsed = -parsed_loc+i;
3576 }
3577 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578}
3579
Michal Vasko730dfdf2015-08-11 14:48:05 +02003580/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003581 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003582 *
Michal Vaskocf024702015-10-08 15:01:42 +02003583 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003584 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003585 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003586 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003587 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003588 */
Michal Vasko184521f2015-09-24 13:14:26 +02003589static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003590resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003591{
Radek Krejci71b795b2015-08-10 16:20:39 +02003592 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003593 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003594 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003595 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003596
Michal Vaskocf024702015-10-08 15:01:42 +02003597 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003598
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003600 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003601
3602 /* searching for nodeset */
3603 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003604 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 +01003605 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003606 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607 goto error;
3608 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003610 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003611
Michal Vasko23b61ec2015-08-19 11:19:50 +02003612 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003613 if (parent_times > 0) {
3614 data = node;
3615 for (i = 1; i < parent_times; ++i) {
3616 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003617 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003618 } else if (!parent_times) {
3619 data = node->child;
3620 } else {
3621 /* absolute path */
3622 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003623 }
3624
Michal Vaskobfd98e62016-09-02 09:50:05 +02003625 /* we may still be parsing it and the pointer is not correct yet */
3626 if (data->prev) {
3627 while (data->prev->next) {
3628 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003629 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630 }
3631 }
3632
3633 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003634 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003635 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003636 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003637 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003638 goto error;
3639 }
3640
3641 if (has_predicate) {
3642 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003643 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003644 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3645 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003646 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003647 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003648 continue;
3649 }
3650
3651 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003652 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003653 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003654 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003655 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003656 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003657 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658 goto error;
3659 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003660 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003661 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662
Michal Vasko23b61ec2015-08-19 11:19:50 +02003663 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003664 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003665 goto error;
3666 }
3667 }
3668 } while (path[0] != '\0');
3669
Michal Vaskof02e3742015-08-05 16:27:02 +02003670 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003671
3672error:
3673
Michal Vaskocf024702015-10-08 15:01:42 +02003674 free(ret->node);
3675 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003676 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677
Michal Vasko0491ab32015-08-19 14:28:29 +02003678 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679}
3680
Michal Vaskoe27516a2016-10-10 17:55:31 +00003681static int
Michal Vasko1c007172017-03-10 10:20:44 +01003682resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003683{
3684 int dep1, dep2;
3685 const struct lys_node *node;
3686
3687 if (lys_parent(op_node)) {
3688 /* inner operation (notif/action) */
3689 if (abs_path) {
3690 return 1;
3691 } else {
3692 /* compare depth of both nodes */
3693 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3694 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3695 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3696 return 1;
3697 }
3698 }
3699 } else {
3700 /* top-level operation (notif/rpc) */
3701 if (op_node != first_node) {
3702 return 1;
3703 }
3704 }
3705
3706 return 0;
3707}
3708
Michal Vasko730dfdf2015-08-11 14:48:05 +02003709/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003710 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003711 *
Michal Vaskobb211122015-08-19 14:03:11 +02003712 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003713 * @param[in] context_node Predicate context node (where the predicate is placed).
3714 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003715 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003716 *
Michal Vasko184521f2015-09-24 13:14:26 +02003717 * @return 0 on forward reference, otherwise the number
3718 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003719 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003720 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003721static int
Michal Vasko1c007172017-03-10 10:20:44 +01003722resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3723 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003724{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003725 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003726 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003727 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003728 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3729 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003730
3731 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003732 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003733 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003734 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003735 return -parsed+i;
3736 }
3737 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003738 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003739
Michal Vasko58090902015-08-13 14:04:15 +02003740 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003741 if (sour_pref) {
3742 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3743 } else {
3744 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003745 }
Michal Vaskobb520442017-05-23 10:55:18 +02003746 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003747 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003748 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003749 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003750 }
3751
3752 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003753 dest_parent_times = 0;
3754 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003755 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3756 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003757 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 +02003758 return -parsed;
3759 }
3760 pke_parsed += i;
3761
Radek Krejciadb57612016-02-16 13:34:34 +01003762 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003763 /* path is supposed to be evaluated in data tree, so we have to skip
3764 * all schema nodes that cannot be instantiated in data tree */
3765 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003766 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003767 dst_node = lys_parent(dst_node));
3768
Michal Vasko1f76a282015-08-04 16:16:53 +02003769 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003770 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003771 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 }
3773 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003774 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003775 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003776 if (dest_pref) {
3777 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3778 } else {
3779 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003780 }
Michal Vaskobb520442017-05-23 10:55:18 +02003781 rc = lys_getnext_data(trg_mod, dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003782 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003783 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003784 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003785 }
3786
Michal Vaskoe27516a2016-10-10 17:55:31 +00003787 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003788 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003789 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003790 }
3791 first_iter = 0;
3792 }
3793
Michal Vasko1f76a282015-08-04 16:16:53 +02003794 if (pke_len == pke_parsed) {
3795 break;
3796 }
3797
Michal Vaskobb520442017-05-23 10:55:18 +02003798 if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vasko1f76a282015-08-04 16:16:53 +02003799 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003800 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003801 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003802 return -parsed;
3803 }
3804 pke_parsed += i;
3805 }
3806
3807 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003808 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003809 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003810 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003811 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003812 return -parsed;
3813 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003814 } while (has_predicate);
3815
3816 return parsed;
3817}
3818
Michal Vasko730dfdf2015-08-11 14:48:05 +02003819/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003820 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003821 *
Michal Vaskobb211122015-08-19 14:03:11 +02003822 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003823 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003824 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003825 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003826 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003827 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003828static int
Michal Vasko1c007172017-03-10 10:20:44 +01003829resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003830{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003831 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003832 struct lys_node_augment *last_aug;
3833 const struct lys_module *cur_mod;
Radek Krejci990af1f2016-11-09 13:53:36 +01003834 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003835 const char *id, *prefix, *name;
3836 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003837 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003838
Michal Vasko184521f2015-09-24 13:14:26 +02003839 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003840 parent_times = 0;
3841 id = path;
3842
Michal Vasko1c007172017-03-10 10:20:44 +01003843 /* find operation schema we are in */
3844 for (op_node = lys_parent(parent);
3845 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3846 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003847
Radek Krejci990af1f2016-11-09 13:53:36 +01003848 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003849 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003850 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko1c007172017-03-10 10:20:44 +01003851 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003852 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003853 }
3854 id += i;
3855
Michal Vaskobb520442017-05-23 10:55:18 +02003856 /* get the current module */
3857 cur_mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3858 if (!cur_mod) {
3859 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3860 return EXIT_FAILURE;
3861 }
3862 last_aug = NULL;
3863
Michal Vasko184521f2015-09-24 13:14:26 +02003864 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003865 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003866 /* use module data */
3867 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003868
Michal Vasko1f76a282015-08-04 16:16:53 +02003869 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003870 /* we are looking for the right parent */
3871 for (i = 0, node = parent; i < parent_times; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003872 /* path is supposed to be evaluated in data tree, so we have to skip
3873 * all schema nodes that cannot be instantiated in data tree */
3874 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003875 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003876 node = lys_parent(node));
3877
Michal Vasko1f76a282015-08-04 16:16:53 +02003878 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003879 if (i == parent_times - 1) {
3880 /* top-level */
3881 break;
3882 }
3883
3884 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003885 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003886 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003887 }
3888 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003889 } else {
3890 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003891 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003892 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003893 }
3894
Michal Vaskobb520442017-05-23 10:55:18 +02003895 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3896 * - useless to search for that in augments) */
3897 if (!cur_mod->implemented && node) {
3898get_next_augment:
3899 last_aug = lys_getnext_target_aug(last_aug, cur_mod, node);
3900 }
3901
3902 rc = lys_getnext_data(cur_mod, (last_aug ? (struct lys_node *)last_aug : node), name, nam_len, LYS_LIST
3903 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003904 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003905 if (last_aug) {
3906 goto get_next_augment;
3907 }
Michal Vasko1c007172017-03-10 10:20:44 +01003908 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003909 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003910 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003911
Michal Vaskoe27516a2016-10-10 17:55:31 +00003912 if (first_iter) {
3913 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003914 if (op_node && parent_times &&
3915 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003916 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003917 }
3918 first_iter = 0;
3919 }
3920
Michal Vasko1f76a282015-08-04 16:16:53 +02003921 if (has_predicate) {
3922 /* we have predicate, so the current result must be list */
3923 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003924 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003925 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003926 }
3927
Michal Vasko1c007172017-03-10 10:20:44 +01003928 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003929 if (!i) {
3930 return EXIT_FAILURE;
3931 } else if (i < 0) {
3932 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003933 }
3934 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003935 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003936 }
3937 } while (id[0]);
3938
Michal Vaskoca917682016-07-25 11:00:37 +02003939 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003940 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003941 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003942 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 +02003943 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003944 }
3945
Radek Krejcicf509982015-12-15 09:22:44 +01003946 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003947 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003948 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003949 return -1;
3950 }
3951
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003952 if (ret) {
3953 *ret = node;
3954 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003955
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003956 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003957}
3958
Michal Vasko730dfdf2015-08-11 14:48:05 +02003959/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003960 * @brief Resolve instance-identifier predicate in JSON data format.
3961 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003962 *
Michal Vaskobb211122015-08-19 14:03:11 +02003963 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003964 * @param[in,out] node_match Nodes matching the restriction without
3965 * the predicate. Nodes not satisfying
3966 * the predicate are removed.
3967 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003968 * @return Number of characters successfully parsed,
3969 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003970 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003971static int
Michal Vasko1c007172017-03-10 10:20:44 +01003972resolve_instid_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003974 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003975 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003976 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003977 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003978 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003979
Michal Vasko1f2cc332015-08-19 11:18:32 +02003980 assert(pred && node_match->count);
3981
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003982 idx = -1;
3983 parsed = 0;
3984
Michal Vaskob2f40be2016-09-08 16:03:48 +02003985 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003986 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003987 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003988 return -parsed+i;
3989 }
3990 parsed += i;
3991 pred += i;
3992
3993 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003994 /* pos */
3995 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003996 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003997 } else if (name[0] != '.') {
3998 /* list keys */
3999 if (pred_iter < 0) {
4000 pred_iter = 1;
4001 } else {
4002 ++pred_iter;
4003 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004004 }
4005
Michal Vaskof2f28a12016-09-09 12:43:06 +02004006 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004007 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004008 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004009 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004010 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004011 goto remove_instid;
4012 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004013
4014 target = node_match->node[j];
4015 /* check the value */
4016 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4017 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4018 goto remove_instid;
4019 }
4020
4021 } else if (!value) {
4022 /* keyless list position */
4023 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4024 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4025 goto remove_instid;
4026 }
4027
4028 if (idx != cur_idx) {
4029 goto remove_instid;
4030 }
4031
4032 } else {
4033 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004034 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004035 goto remove_instid;
4036 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004037
4038 /* key module must match the list module */
4039 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4040 || node_match->node[j]->schema->module->name[mod_len]) {
4041 goto remove_instid;
4042 }
4043 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004044 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004045 if (!target) {
4046 goto remove_instid;
4047 }
4048 if ((struct lys_node_leaf *)target->schema !=
4049 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4050 goto remove_instid;
4051 }
4052
4053 /* check the value */
4054 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4055 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4056 goto remove_instid;
4057 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058 }
4059
Michal Vaskob2f40be2016-09-08 16:03:48 +02004060 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004061 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004062 continue;
4063
4064remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004065 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004066 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004067 }
4068 } while (has_predicate);
4069
Michal Vaskob2f40be2016-09-08 16:03:48 +02004070 /* check that all list keys were specified */
4071 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004072 j = 0;
4073 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004074 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4075 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4076 /* not enough predicates, just remove the list instance */
4077 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004078 } else {
4079 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004080 }
4081 }
4082
4083 if (!node_match->count) {
4084 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4085 }
4086 }
4087
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004088 return parsed;
4089}
4090
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004091int
Michal Vasko769f8032017-01-24 13:11:55 +01004092lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004093{
4094 struct lys_node *parent, *elem;
4095 struct lyxp_set set;
4096 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004097 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004098
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004099 if (check_place) {
4100 parent = node;
4101 while (parent) {
4102 if (parent->nodetype == LYS_GROUPING) {
4103 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004104 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004105 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004106 if (parent->nodetype == LYS_AUGMENT) {
4107 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004108 /* unresolved augment, skip for now (will be checked later) */
4109 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004110 } else {
4111 parent = ((struct lys_node_augment *)parent)->target;
4112 continue;
4113 }
4114 }
4115 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004116 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004117 }
4118
Michal Vasko769f8032017-01-24 13:11:55 +01004119 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4120 if (ret == -1) {
4121 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004122 }
4123
4124 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4125
4126 for (i = 0; i < set.used; ++i) {
4127 /* skip roots'n'stuff */
4128 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4129 /* XPath expression cannot reference "lower" status than the node that has the definition */
4130 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4131 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4132 return -1;
4133 }
4134
4135 if (parent) {
4136 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4137 if (!elem) {
4138 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004139 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004140 break;
4141 }
4142 }
4143 }
4144 }
4145
4146 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004147 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004148}
4149
Radek Krejcif71f48f2016-10-25 16:37:24 +02004150static int
4151check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4152{
4153 int i;
4154
4155 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004156 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4157 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004158 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
Radek Krejcif71f48f2016-10-25 16:37:24 +02004159 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4160 return -1;
4161 }
4162 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4163 * of leafref resolving (lys_leaf_add_leafref_target()) */
4164 } else if (type->base == LY_TYPE_UNION) {
4165 for (i = 0; i < type->info.uni.count; i++) {
4166 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4167 return -1;
4168 }
4169 }
4170 }
4171 return 0;
4172}
4173
Michal Vasko9e635ac2016-10-17 11:44:09 +02004174/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004175 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004176 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004177 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004178 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004179 * @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 +02004180 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004181 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004182 *
4183 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004184 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004185int
4186inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004187{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004188 struct lys_node_leaf *leaf;
4189
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004190 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004191 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004192 if (clear) {
4193 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004194 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004195 } else {
4196 if (node->flags & LYS_CONFIG_SET) {
4197 /* skip nodes with an explicit config value */
4198 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4199 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004200 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004201 return -1;
4202 }
4203 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004204 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004205
4206 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4207 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4208 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004209 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4210 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004211 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4212 return -1;
4213 }
4214 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004215 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004216 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004217 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004218 return -1;
4219 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004220 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4221 leaf = (struct lys_node_leaf *)node;
4222 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004223 return -1;
4224 }
4225 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004226 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004227
4228 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004229}
4230
Michal Vasko730dfdf2015-08-11 14:48:05 +02004231/**
Michal Vasko7178e692016-02-12 15:58:05 +01004232 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004233 *
Michal Vaskobb211122015-08-19 14:03:11 +02004234 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004235 * @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 +01004236 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004237 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004238 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004239 */
Michal Vasko7178e692016-02-12 15:58:05 +01004240static int
Radek Krejcib3142312016-11-09 11:04:12 +01004241resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004242{
Michal Vasko44ab1462017-05-18 13:18:36 +02004243 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004244 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004245 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004246
Michal Vasko2ef7db62017-06-12 09:24:02 +02004247 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004248 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004249
Michal Vaskobb520442017-05-23 10:55:18 +02004250 /* set it as not applied for now */
4251 aug->flags |= LYS_NOTAPPLIED;
4252
Michal Vasko2ef7db62017-06-12 09:24:02 +02004253 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004254 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004255 /* resolve target node */
4256 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module),
4257 (const struct lys_node **)&aug->target);
4258 if (rc == -1) {
4259 return -1;
4260 } else if (rc > 0) {
4261 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4262 return -1;
4263 }
4264 if (!aug->target) {
4265 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4266 return EXIT_FAILURE;
4267 }
Michal Vasko15b36692016-08-26 15:29:54 +02004268 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004269
Michal Vaskod58d5962016-03-02 14:29:41 +01004270 /* check for mandatory nodes - if the target node is in another module
4271 * the added nodes cannot be mandatory
4272 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004273 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4274 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004275 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004276 }
4277
Michal Vasko07e89ef2016-03-03 13:28:57 +01004278 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004279 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004280 LY_TREE_FOR(aug->child, sub) {
4281 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4282 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4283 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4284 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004285 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004286 return -1;
4287 }
4288 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004289 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004290 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004291 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004292 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004293 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004294 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004295 return -1;
4296 }
4297 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004298 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004299 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004300 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004301 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004302 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004303 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004304 return -1;
4305 }
4306 }
4307 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004308 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004309 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004310 return -1;
4311 }
4312
Radek Krejcic071c542016-01-27 14:57:51 +01004313 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004314 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004315 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004316 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004317 }
4318 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004319
Michal Vasko44ab1462017-05-18 13:18:36 +02004320 if (!aug->child) {
4321 /* empty augment, nothing to connect, but it is techincally applied */
4322 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4323 aug->flags &= ~LYS_NOTAPPLIED;
4324 } else if (mod->implemented && apply_aug(aug, unres)) {
4325 /* we tried to connect it, we failed */
4326 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004327 }
4328
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004329 return EXIT_SUCCESS;
4330}
4331
Radek Krejcie534c132016-11-23 13:32:31 +01004332static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004333resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004334{
4335 enum LY_VLOG_ELEM vlog_type;
4336 void *vlog_node;
4337 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004338 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004339 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004340 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004341 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004342 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004343 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004344
4345 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004346 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004347 vlog_node = info->parent;
4348 vlog_type = LY_VLOG_LYS;
4349 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004350 case LYEXT_PAR_MODULE:
4351 case LYEXT_PAR_IMPORT:
4352 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004353 vlog_node = NULL;
4354 vlog_type = LY_VLOG_LYS;
4355 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004356 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004357 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004358 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004359 break;
4360 }
4361
4362 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004363 /* YIN */
4364
Radek Krejcie534c132016-11-23 13:32:31 +01004365 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004366 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004367 if (!mod) {
4368 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004369 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004370 }
4371
4372 /* find the extension definition */
4373 e = NULL;
4374 for (i = 0; i < mod->extensions_size; i++) {
4375 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4376 e = &mod->extensions[i];
4377 break;
4378 }
4379 }
4380 /* try submodules */
4381 for (j = 0; !e && j < mod->inc_size; j++) {
4382 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4383 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4384 e = &mod->inc[j].submodule->extensions[i];
4385 break;
4386 }
4387 }
4388 }
4389 if (!e) {
4390 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4391 return EXIT_FAILURE;
4392 }
4393
4394 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004395
Radek Krejci72b35992017-01-04 16:27:44 +01004396 if (e->plugin && e->plugin->check_position) {
4397 /* common part - we have plugin with position checking function, use it first */
4398 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4399 /* extension is not allowed here */
4400 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4401 return -1;
4402 }
4403 }
4404
Radek Krejci8d6b7422017-02-03 14:42:13 +01004405 /* extension type-specific part - allocation */
4406 if (e->plugin) {
4407 etype = e->plugin->type;
4408 } else {
4409 /* default type */
4410 etype = LYEXT_FLAG;
4411 }
4412 switch (etype) {
4413 case LYEXT_FLAG:
4414 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4415 break;
4416 case LYEXT_COMPLEX:
4417 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4418 break;
4419 case LYEXT_ERR:
4420 /* we never should be here */
4421 LOGINT;
4422 return -1;
4423 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02004424 LY_CHECK_ERR_RETURN(!*ext, LOGMEM, -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004425
4426 /* common part for all extension types */
4427 (*ext)->def = e;
4428 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004429 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004430 (*ext)->insubstmt = info->substmt;
4431 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004432 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004433
4434 if (!(e->flags & LYS_YINELEM) && e->argument) {
4435 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4436 if (!(*ext)->arg_value) {
4437 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4438 return -1;
4439 }
4440 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4441 }
4442
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004443 (*ext)->nodetype = LYS_EXT;
4444 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004445
Radek Krejci8d6b7422017-02-03 14:42:13 +01004446 /* extension type-specific part - parsing content */
4447 switch (etype) {
4448 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004449 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4450 if (!yin->ns) {
4451 /* garbage */
4452 lyxml_free(mod->ctx, yin);
4453 continue;
4454 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4455 /* standard YANG statements are not expected here */
4456 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4457 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004458 } else if (yin->ns == info->data.yin->ns &&
4459 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004460 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004461 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004462 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004463 return -1;
4464 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004465 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004466 yin->content = NULL;
4467 lyxml_free(mod->ctx, yin);
4468 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004469 /* extension instance */
4470 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4471 LYEXT_SUBSTMT_SELF, 0, unres)) {
4472 return -1;
4473 }
Radek Krejci72b35992017-01-04 16:27:44 +01004474
Radek Krejci72b35992017-01-04 16:27:44 +01004475 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004476 }
Radek Krejci72b35992017-01-04 16:27:44 +01004477 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004478 break;
4479 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004480 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004481 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4482 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004483 return -1;
4484 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004485 break;
4486 default:
4487 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004488 }
Radek Krejci72b35992017-01-04 16:27:44 +01004489
4490 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4491
Radek Krejcie534c132016-11-23 13:32:31 +01004492 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004493 /* YANG */
4494
PavolVicanc1807262017-01-31 18:00:27 +01004495 ext_prefix = (char *)(*ext)->def;
4496 tmp = strchr(ext_prefix, ':');
4497 if (!tmp) {
4498 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004499 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004500 }
4501 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004502
PavolVicanc1807262017-01-31 18:00:27 +01004503 /* get the module where the extension is supposed to be defined */
4504 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4505 if (!mod) {
4506 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4507 return EXIT_FAILURE;
4508 }
4509
4510 /* find the extension definition */
4511 e = NULL;
4512 for (i = 0; i < mod->extensions_size; i++) {
4513 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4514 e = &mod->extensions[i];
4515 break;
4516 }
4517 }
4518 /* try submodules */
4519 for (j = 0; !e && j < mod->inc_size; j++) {
4520 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4521 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4522 e = &mod->inc[j].submodule->extensions[i];
4523 break;
4524 }
4525 }
4526 }
4527 if (!e) {
4528 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4529 return EXIT_FAILURE;
4530 }
4531
4532 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4533
4534 if (e->plugin && e->plugin->check_position) {
4535 /* common part - we have plugin with position checking function, use it first */
4536 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4537 /* extension is not allowed here */
4538 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004539 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004540 }
4541 }
4542
PavolVican22e88682017-02-14 22:38:18 +01004543 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004544 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004545 (*ext)->def = e;
4546 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004547 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004548
PavolVicanb0d84102017-02-15 16:32:42 +01004549 if (e->argument && !(*ext)->arg_value) {
4550 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4551 goto error;
4552 }
4553
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004554 (*ext)->module = info->mod;
4555 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004556
PavolVican22e88682017-02-14 22:38:18 +01004557 /* extension type-specific part */
4558 if (e->plugin) {
4559 etype = e->plugin->type;
4560 } else {
4561 /* default type */
4562 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004563 }
PavolVican22e88682017-02-14 22:38:18 +01004564 switch (etype) {
4565 case LYEXT_FLAG:
4566 /* nothing change */
4567 break;
4568 case LYEXT_COMPLEX:
4569 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004570 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM, error);
PavolVican22e88682017-02-14 22:38:18 +01004571 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4572 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004573 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004574 if (info->data.yang) {
4575 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004576 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4577 (struct lys_ext_instance_complex*)(*ext))) {
4578 goto error;
4579 }
4580 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4581 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004582 goto error;
4583 }
PavolVicana3876672017-02-21 15:49:51 +01004584 }
4585 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4586 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004587 }
PavolVican22e88682017-02-14 22:38:18 +01004588 break;
4589 case LYEXT_ERR:
4590 /* we never should be here */
4591 LOGINT;
4592 goto error;
4593 }
4594
PavolVican22e88682017-02-14 22:38:18 +01004595 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4596 goto error;
4597 }
4598 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004599 }
4600
4601 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004602error:
4603 free(ext_prefix);
4604 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004605}
4606
Michal Vasko730dfdf2015-08-11 14:48:05 +02004607/**
Pavol Vican855ca622016-09-05 13:07:54 +02004608 * @brief Resolve (find) choice default case. Does not log.
4609 *
4610 * @param[in] choic Choice to use.
4611 * @param[in] dflt Name of the default case.
4612 *
4613 * @return Pointer to the default node or NULL.
4614 */
4615static struct lys_node *
4616resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4617{
4618 struct lys_node *child, *ret;
4619
4620 LY_TREE_FOR(choic->child, child) {
4621 if (child->nodetype == LYS_USES) {
4622 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4623 if (ret) {
4624 return ret;
4625 }
4626 }
4627
4628 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004629 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004630 return child;
4631 }
4632 }
4633
4634 return NULL;
4635}
4636
4637/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004638 * @brief Resolve uses, apply augments, refines. Logs directly.
4639 *
Michal Vaskobb211122015-08-19 14:03:11 +02004640 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004641 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004642 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004643 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004644 */
Michal Vasko184521f2015-09-24 13:14:26 +02004645static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004646resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004647{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004648 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004649 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004650 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004651 struct lys_node_leaflist *llist;
4652 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004653 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004654 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004655 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004656 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004657 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004658 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004659
Michal Vasko71e1aa82015-08-12 12:17:51 +02004660 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004661
4662 /* HACK just check that the grouping is resolved
4663 * - the higher byte in flags is always empty in grouping (no flags there apply to the groupings)
4664 * so we use it to count unresolved uses inside the grouping */
4665#if __BYTE_ORDER == __LITTLE_ENDIAN
4666 assert(!((uint8_t*)&uses->grp->flags)[1]);
4667#else
4668 assert(!((uint8_t*)&uses->grp->flags)[0]);
4669#endif
Michal Vasko71e1aa82015-08-12 12:17:51 +02004670
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004671 if (!uses->grp->child) {
4672 /* grouping without children, warning was already displayed */
4673 return EXIT_SUCCESS;
4674 }
4675
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004676 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004677 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004678 if (node_aux->nodetype & LYS_GROUPING) {
4679 /* do not instantiate groupings from groupings */
4680 continue;
4681 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004682 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004683 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004684 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004685 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004686 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004687 }
Pavol Vican55abd332016-07-12 15:54:49 +02004688 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004689 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 +02004690 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004691 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004692 }
4693 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004694 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004695
Michal Vaskodef0db12015-10-07 13:22:48 +02004696 /* we managed to copy the grouping, the rest must be possible to resolve */
4697
Pavol Vican855ca622016-09-05 13:07:54 +02004698 if (uses->refine_size) {
4699 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004700 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004701 }
4702
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004703 /* apply refines */
4704 for (i = 0; i < uses->refine_size; i++) {
4705 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004706 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4707 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004708 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004709 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004710 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004711 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004712 }
4713
Radek Krejci1d82ef62015-08-07 14:44:40 +02004714 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004715 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004716 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004717 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004718 }
Pavol Vican855ca622016-09-05 13:07:54 +02004719 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004720
4721 /* description on any nodetype */
4722 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004723 lydict_remove(ctx, node->dsc);
4724 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004725 }
4726
4727 /* reference on any nodetype */
4728 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004729 lydict_remove(ctx, node->ref);
4730 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004731 }
4732
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004733 /* config on any nodetype,
4734 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4735 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004736 node->flags &= ~LYS_CONFIG_MASK;
4737 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004738 }
4739
4740 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004741 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004742 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004743 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004744 leaf = (struct lys_node_leaf *)node;
4745
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004746 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004747 lydict_remove(ctx, leaf->dflt);
4748 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4749
4750 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004751 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4752 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004753 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004754 }
Radek Krejci200bf712016-08-16 17:11:04 +02004755 } else if (node->nodetype == LYS_LEAFLIST) {
4756 /* leaf-list */
4757 llist = (struct lys_node_leaflist *)node;
4758
4759 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004760 for (j = 0; j < llist->dflt_size; j++) {
4761 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004762 }
4763 free(llist->dflt);
4764
4765 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02004766 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
4767 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM, fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004768 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004769 for (j = 0; j < llist->dflt_size; j++) {
4770 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004771 }
4772
4773 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004774 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004775 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004776 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004777 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004778 }
4779 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004780 }
4781 }
4782
4783 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004784 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004785 /* remove current value */
4786 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004787
Radek Krejcibf285832017-01-26 16:05:41 +01004788 /* set new value */
4789 node->flags |= (rfn->flags & LYS_MAND_MASK);
4790
Pavol Vican855ca622016-09-05 13:07:54 +02004791 if (rfn->flags & LYS_MAND_TRUE) {
4792 /* check if node has default value */
4793 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004794 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4795 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004796 goto fail;
4797 }
4798 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004799 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4800 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004801 goto fail;
4802 }
4803 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004804 }
4805
4806 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004807 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4808 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4809 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004810 }
4811
4812 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004813 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004814 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004815 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004816 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004817 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004818 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004819 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004820 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004821 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004822 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004823 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004824 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004825 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004826 }
4827 }
4828
4829 /* must in leaf, leaf-list, list, container or anyxml */
4830 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004831 switch (node->nodetype) {
4832 case LYS_LEAF:
4833 old_size = &((struct lys_node_leaf *)node)->must_size;
4834 old_must = &((struct lys_node_leaf *)node)->must;
4835 break;
4836 case LYS_LEAFLIST:
4837 old_size = &((struct lys_node_leaflist *)node)->must_size;
4838 old_must = &((struct lys_node_leaflist *)node)->must;
4839 break;
4840 case LYS_LIST:
4841 old_size = &((struct lys_node_list *)node)->must_size;
4842 old_must = &((struct lys_node_list *)node)->must;
4843 break;
4844 case LYS_CONTAINER:
4845 old_size = &((struct lys_node_container *)node)->must_size;
4846 old_must = &((struct lys_node_container *)node)->must;
4847 break;
4848 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004849 case LYS_ANYDATA:
4850 old_size = &((struct lys_node_anydata *)node)->must_size;
4851 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004852 break;
4853 default:
4854 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004855 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004856 }
4857
4858 size = *old_size + rfn->must_size;
4859 must = realloc(*old_must, size * sizeof *rfn->must);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004860 LY_CHECK_ERR_GOTO(!must, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004861 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004862 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004863 lys_ext_dup(rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejci5138e9f2017-04-12 13:10:46 +02004864 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004865 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4866 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4867 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4868 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4869 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004870 }
4871
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004872 *old_must = must;
4873 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004874
4875 /* check XPath dependencies again */
4876 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4877 goto fail;
4878 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004879 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004880
4881 /* if-feature in leaf, leaf-list, list, container or anyxml */
4882 if (rfn->iffeature_size) {
4883 old_size = &node->iffeature_size;
4884 old_iff = &node->iffeature;
4885
4886 size = *old_size + rfn->iffeature_size;
4887 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004888 LY_CHECK_ERR_GOTO(!iff, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004889 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4890 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004891 if (usize1) {
4892 /* there is something to duplicate */
4893 /* duplicate compiled expression */
4894 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4895 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004896 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004897 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004898
4899 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004900 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004901 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004902 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004903 }
4904 }
4905
4906 *old_iff = iff;
4907 *old_size = size;
4908 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004909 }
4910
4911 /* apply augments */
4912 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004913 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004914 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004915 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004916 }
4917 }
4918
Pavol Vican855ca622016-09-05 13:07:54 +02004919 /* check refines */
4920 for (i = 0; i < uses->refine_size; i++) {
4921 node = refine_nodes[i];
4922 rfn = &uses->refine[i];
4923
4924 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004925 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004926 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004927 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004928 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4929 (rfn->flags & LYS_CONFIG_W)) {
4930 /* setting config true under config false is prohibited */
4931 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004932 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004933 "changing config from 'false' to 'true' is prohibited while "
4934 "the target's parent is still config 'false'.");
4935 goto fail;
4936 }
4937
4938 /* inherit config change to the target children */
4939 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4940 if (rfn->flags & LYS_CONFIG_W) {
4941 if (iter->flags & LYS_CONFIG_SET) {
4942 /* config is set explicitely, go to next sibling */
4943 next = NULL;
4944 goto nextsibling;
4945 }
4946 } else { /* LYS_CONFIG_R */
4947 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4948 /* error - we would have config data under status data */
4949 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004950 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004951 "changing config from 'true' to 'false' is prohibited while the target "
4952 "has still a children with explicit config 'true'.");
4953 goto fail;
4954 }
4955 }
4956 /* change config */
4957 iter->flags &= ~LYS_CONFIG_MASK;
4958 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4959
4960 /* select next iter - modified LY_TREE_DFS_END */
4961 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4962 next = NULL;
4963 } else {
4964 next = iter->child;
4965 }
4966nextsibling:
4967 if (!next) {
4968 /* try siblings */
4969 next = iter->next;
4970 }
4971 while (!next) {
4972 /* parent is already processed, go to its sibling */
4973 iter = lys_parent(iter);
4974
4975 /* no siblings, go back through parents */
4976 if (iter == node) {
4977 /* we are done, no next element to process */
4978 break;
4979 }
4980 next = iter->next;
4981 }
4982 }
4983 }
4984
4985 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004986 if (rfn->dflt_size) {
4987 if (node->nodetype == LYS_CHOICE) {
4988 /* choice */
4989 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4990 rfn->dflt[0]);
4991 if (!((struct lys_node_choice *)node)->dflt) {
4992 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4993 goto fail;
4994 }
4995 if (lyp_check_mandatory_choice(node)) {
4996 goto fail;
4997 }
Pavol Vican855ca622016-09-05 13:07:54 +02004998 }
4999 }
5000
5001 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005002 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005003 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005004 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5005 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005006 goto fail;
5007 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005008 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005009 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005010 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5011 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005012 goto fail;
5013 }
5014 }
5015
5016 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005017 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005018 if (node->nodetype == LYS_LEAFLIST) {
5019 llist = (struct lys_node_leaflist *)node;
5020 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005021 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5022 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005023 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5024 goto fail;
5025 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005026 } else if (node->nodetype == LYS_LEAF) {
5027 leaf = (struct lys_node_leaf *)node;
5028 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02005029 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5030 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005031 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5032 goto fail;
5033 }
Pavol Vican855ca622016-09-05 13:07:54 +02005034 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005035
Pavol Vican855ca622016-09-05 13:07:54 +02005036 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005037 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005038 for (parent = node->parent;
5039 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5040 parent = parent->parent) {
5041 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5042 /* stop also on presence containers */
5043 break;
5044 }
5045 }
5046 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5047 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5048 if (lyp_check_mandatory_choice(parent)) {
5049 goto fail;
5050 }
5051 }
5052 }
5053 }
5054 free(refine_nodes);
5055
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005056 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005057
5058fail:
5059 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5060 lys_node_free(iter, NULL, 0);
5061 }
Pavol Vican855ca622016-09-05 13:07:54 +02005062 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005063 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005064}
5065
Radek Krejci83a4bac2017-02-07 15:53:04 +01005066void
5067resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005068{
5069 int i;
5070
5071 assert(der && base);
5072
Radek Krejci018f1f52016-08-03 16:01:20 +02005073 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005074 /* create a set for backlinks if it does not exist */
5075 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005076 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005077 /* store backlink */
5078 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005079
Radek Krejci85a54be2016-10-20 12:39:56 +02005080 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005081 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005082 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005083 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005084}
5085
Michal Vasko730dfdf2015-08-11 14:48:05 +02005086/**
5087 * @brief Resolve base identity recursively. Does not log.
5088 *
5089 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005090 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005091 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005092 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005093 *
Radek Krejci219fa612016-08-15 10:36:51 +02005094 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005095 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005096static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005097resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005098 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005099{
Michal Vaskof02e3742015-08-05 16:27:02 +02005100 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005101 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005102
Radek Krejcicf509982015-12-15 09:22:44 +01005103 assert(ret);
5104
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005105 /* search module */
5106 for (i = 0; i < module->ident_size; i++) {
5107 if (!strcmp(basename, module->ident[i].name)) {
5108
5109 if (!ident) {
5110 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005111 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005112 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005113 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005114 }
5115
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005116 base = &module->ident[i];
5117 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005118 }
5119 }
5120
5121 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005122 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5123 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5124 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005125
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005126 if (!ident) {
5127 *ret = &module->inc[j].submodule->ident[i];
5128 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005129 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005130
5131 base = &module->inc[j].submodule->ident[i];
5132 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005133 }
5134 }
5135 }
5136
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005137matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005138 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005139 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005140 /* is it already completely resolved? */
5141 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005142 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005143 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5144
5145 /* simple check for circular reference,
5146 * the complete check is done as a side effect of using only completely
5147 * resolved identities (previous check of unres content) */
5148 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5149 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5150 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005151 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005152 }
5153
Radek Krejci06f64ed2016-08-15 11:07:44 +02005154 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005155 }
5156 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005157
Radek Krejcibabbff82016-02-19 13:31:37 +01005158 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005159 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005160 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005161 }
5162
Radek Krejci219fa612016-08-15 10:36:51 +02005163 /* base not found (maybe a forward reference) */
5164 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005165}
5166
Michal Vasko730dfdf2015-08-11 14:48:05 +02005167/**
5168 * @brief Resolve base identity. Logs directly.
5169 *
5170 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005171 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005172 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005173 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005174 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005175 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005176 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005177 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005178static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005179resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005180 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005181{
5182 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005183 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005184 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005185 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005186 struct lys_module *mod;
5187
5188 assert((ident && !type) || (!ident && type));
5189
5190 if (!type) {
5191 /* have ident to resolve */
5192 ret = &target;
5193 flags = ident->flags;
5194 mod = ident->module;
5195 } else {
5196 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005197 ++type->info.ident.count;
5198 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
Radek Krejciaa1303c2017-05-31 13:57:37 +02005199 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM, -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005200
5201 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005202 flags = type->parent->flags;
5203 mod = type->parent->module;
5204 }
Michal Vaskof2006002016-04-21 16:28:15 +02005205 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005206
5207 /* search for the base identity */
5208 name = strchr(basename, ':');
5209 if (name) {
5210 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005211 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212 name++;
5213
Michal Vasko2d851a92015-10-20 16:16:36 +02005214 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005215 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005216 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005217 }
5218 } else {
5219 name = basename;
5220 }
5221
Radek Krejcic071c542016-01-27 14:57:51 +01005222 /* get module where to search */
5223 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5224 if (!module) {
5225 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005226 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005227 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005228 }
5229
Radek Krejcic071c542016-01-27 14:57:51 +01005230 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005231 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5232 if (!rc) {
5233 assert(*ret);
5234
5235 /* check status */
5236 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5237 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5238 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005239 } else if (ident) {
5240 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005241 if (lys_main_module(mod)->implemented) {
5242 /* in case of the implemented identity, maintain backlinks to it
5243 * from the base identities to make it available when resolving
5244 * data with the identity values (not implemented identity is not
5245 * allowed as an identityref value). */
5246 resolve_identity_backlink_update(ident, *ret);
5247 }
Radek Krejci219fa612016-08-15 10:36:51 +02005248 }
5249 } else if (rc == EXIT_FAILURE) {
5250 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005251 if (type) {
5252 --type->info.ident.count;
5253 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005254 }
5255
Radek Krejci219fa612016-08-15 10:36:51 +02005256 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005257}
5258
Radek Krejci9e6af732017-04-27 14:40:25 +02005259/*
5260 * 1 - true (der is derived from base)
5261 * 0 - false (der is not derived from base)
5262 */
5263static int
5264search_base_identity(struct lys_ident *der, struct lys_ident *base)
5265{
5266 int i;
5267
5268 if (der == base) {
5269 return 1;
5270 } else {
5271 for(i = 0; i < der->base_size; i++) {
5272 if (search_base_identity(der->base[i], base) == 1) {
5273 return 1;
5274 }
5275 }
5276 }
5277
5278 return 0;
5279}
5280
Michal Vasko730dfdf2015-08-11 14:48:05 +02005281/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005282 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005283 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005284 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005285 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005286 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005287 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005288 *
5289 * @return Pointer to the identity resolvent, NULL on error.
5290 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005291struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005292resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005293{
Radek Krejci9e6af732017-04-27 14:40:25 +02005294 const char *mod_name, *name;
5295 int mod_name_len, rc, i, j;
5296 int make_implemented = 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02005297 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005298 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005299 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005300
Radek Krejci9e6af732017-04-27 14:40:25 +02005301 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005302
Michal Vaskof2d43962016-09-02 11:10:16 +02005303 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005304 return NULL;
5305 }
5306
Michal Vaskoc633ca02015-08-21 14:03:51 +02005307 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005308 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005309 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005310 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005311 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005312 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005313 return NULL;
5314 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005315
5316 m = lys_main_module(mod); /* shortcut */
5317 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5318 /* identity is defined in the same module as node */
5319 imod = m;
5320 } else if (dflt) {
5321 /* solving identityref in default definition in schema -
5322 * find the identity's module in the imported modules list to have a correct revision */
5323 for (i = 0; i < mod->imp_size; i++) {
5324 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5325 imod = mod->imp[i].module;
5326 break;
5327 }
5328 }
5329 } else {
5330 /* solving identityref in data - get the (implemented) module from the context */
5331 u = 0;
5332 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5333 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5334 break;
5335 }
5336 }
5337 }
5338 if (!imod) {
5339 goto fail;
5340 }
5341
5342 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5343 /* we are solving default statement in schema AND the type is not referencing the same schema,
5344 * THEN, we may need to make the module with the identity implemented, but only if it really
5345 * contains the identity */
5346 if (!imod->implemented) {
5347 cur = NULL;
5348 /* get the identity in the module */
5349 for (i = 0; i < imod->ident_size; i++) {
5350 if (!strcmp(name, imod->ident[i].name)) {
5351 cur = &imod->ident[i];
5352 break;
5353 }
5354 }
5355 if (!cur) {
5356 /* go through includes */
5357 for (j = 0; j < imod->inc_size; j++) {
5358 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5359 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5360 cur = &imod->inc[j].submodule->ident[i];
5361 break;
5362 }
5363 }
5364 }
5365 if (!cur) {
5366 goto fail;
5367 }
5368 }
5369
5370 /* check that identity is derived from one of the type's base */
5371 while (type->der) {
5372 for (i = 0; i < type->info.ident.count; i++) {
5373 if (search_base_identity(cur, type->info.ident.ref[i])) {
5374 /* cur's base matches the type's base */
5375 make_implemented = 1;
5376 goto match;
5377 }
5378 }
5379 type = &type->der->type;
5380 }
5381 /* matching base not found */
5382 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5383 goto fail;
5384 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005385 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005386
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005387 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005388 while (type->der) {
5389 for (i = 0; i < type->info.ident.count; ++i) {
5390 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005391
Radek Krejci85a54be2016-10-20 12:39:56 +02005392 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005393 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005394 for (u = 0; u < cur->der->number; u++) {
5395 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005396 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005397 /* we have match */
5398 cur = der;
5399 goto match;
5400 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005401 }
5402 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005403 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005404 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005405 }
5406
Radek Krejci9e6af732017-04-27 14:40:25 +02005407fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005408 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005409 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005410
5411match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005412 for (i = 0; i < cur->iffeature_size; i++) {
5413 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005414 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005415 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 +02005416 return NULL;
5417 }
5418 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005419 if (make_implemented) {
5420 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5421 imod->name, cur->name, mod->name);
5422 if (lys_set_implemented(imod)) {
5423 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5424 imod->name, cur->name);
5425 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5426 goto fail;
5427 }
5428 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005429 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005430}
5431
Michal Vasko730dfdf2015-08-11 14:48:05 +02005432/**
Michal Vaskobb211122015-08-19 14:03:11 +02005433 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005434 *
Michal Vaskobb211122015-08-19 14:03:11 +02005435 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005436 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005437 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005438 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005439 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005440static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005441resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005442{
Michal Vasko51917552017-03-08 10:21:34 +01005443 int rc, endian_idx;
Radek Krejci010e54b2016-03-15 09:40:34 +01005444 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005445
Michal Vasko51917552017-03-08 10:21:34 +01005446#if __BYTE_ORDER == __LITTLE_ENDIAN
5447 endian_idx = 1;
5448#else
5449 endian_idx = 0;
5450#endif
5451
Radek Krejci6ff885d2017-01-03 14:06:22 +01005452 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
5453 * in some uses. When we see such a uses, the grouping's higher byte of the flags member (not used in
5454 * grouping) is used to store number of so far unresolved uses. The grouping cannot be used unless this
5455 * counter is decreased back to 0. To remember that the uses already increased grouping's counter, the
Radek Krejci010e54b2016-03-15 09:40:34 +01005456 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005457 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 +02005458
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005459 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005460 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5461 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005462 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005463 return -1;
5464 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005465 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005466 return -1;
5467 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005468 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005469 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5470 * (and smaller flags - it uses only a limited set of flags)
5471 */
Michal Vasko51917552017-03-08 10:21:34 +01005472 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005473 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005474 }
Michal Vasko92981a62016-10-14 10:25:16 +02005475 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005476 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005477 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005478 }
5479
Michal Vasko51917552017-03-08 10:21:34 +01005480 if (((uint8_t*)&uses->grp->flags)[endian_idx]) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005481 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005482 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005483 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005484 } else {
5485 /* instantiate grouping only when it is completely resolved */
5486 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005487 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005488 return EXIT_FAILURE;
5489 }
5490
Radek Krejci48464ed2016-03-17 15:44:09 +01005491 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005492 if (!rc) {
5493 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005494 if (par_grp && (uses->flags & LYS_USESGRP)) {
Michal Vasko51917552017-03-08 10:21:34 +01005495 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005496 LOGINT;
5497 return -1;
5498 }
Michal Vasko51917552017-03-08 10:21:34 +01005499 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[endian_idx]--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005500 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005501 }
Radek Krejcicf509982015-12-15 09:22:44 +01005502
5503 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005504 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005505 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005506 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005507 return -1;
5508 }
5509
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005510 return EXIT_SUCCESS;
5511 }
5512
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005513 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005514}
5515
Michal Vasko730dfdf2015-08-11 14:48:05 +02005516/**
Michal Vasko9957e592015-08-17 15:04:09 +02005517 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005518 *
Michal Vaskobb211122015-08-19 14:03:11 +02005519 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005520 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005521 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005522 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005523 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005524static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005525resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005526{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005527 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005528 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005529
5530 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005531 if (!list->child) {
5532 /* no child, possible forward reference */
5533 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5534 return EXIT_FAILURE;
5535 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005536 /* get the key name */
5537 if ((value = strpbrk(keys_str, " \t\n"))) {
5538 len = value - keys_str;
5539 while (isspace(value[0])) {
5540 value++;
5541 }
5542 } else {
5543 len = strlen(keys_str);
5544 }
5545
Michal Vaskobb520442017-05-23 10:55:18 +02005546 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5547 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005548 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005549 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5550 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005551 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005552
Radek Krejci48464ed2016-03-17 15:44:09 +01005553 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005554 /* check_key logs */
5555 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005556 }
5557
Radek Krejcicf509982015-12-15 09:22:44 +01005558 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005559 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005560 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5561 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005562 return -1;
5563 }
5564
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005565 /* prepare for next iteration */
5566 while (value && isspace(value[0])) {
5567 value++;
5568 }
5569 keys_str = value;
5570 }
5571
Michal Vaskof02e3742015-08-05 16:27:02 +02005572 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005573}
5574
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005575/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005576 * @brief Resolve (check) all must conditions of \p node.
5577 * Logs directly.
5578 *
5579 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005580 * @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 +02005581 *
5582 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5583 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005584static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005585resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005586{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005587 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005588 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005589 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005590 struct lys_restr *must;
5591 struct lyxp_set set;
5592
5593 assert(node);
5594 memset(&set, 0, sizeof set);
5595
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005596 if (inout_parent) {
5597 for (schema = lys_parent(node->schema);
5598 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5599 schema = lys_parent(schema));
5600 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5601 LOGINT;
5602 return -1;
5603 }
5604 must_size = ((struct lys_node_inout *)schema)->must_size;
5605 must = ((struct lys_node_inout *)schema)->must;
5606
Michal Vasko3cfa3182017-01-17 10:00:58 +01005607 node_flags = schema->flags;
5608
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005609 /* context node is the RPC/action */
5610 node = node->parent;
5611 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5612 LOGINT;
5613 return -1;
5614 }
5615 } else {
5616 switch (node->schema->nodetype) {
5617 case LYS_CONTAINER:
5618 must_size = ((struct lys_node_container *)node->schema)->must_size;
5619 must = ((struct lys_node_container *)node->schema)->must;
5620 break;
5621 case LYS_LEAF:
5622 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5623 must = ((struct lys_node_leaf *)node->schema)->must;
5624 break;
5625 case LYS_LEAFLIST:
5626 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5627 must = ((struct lys_node_leaflist *)node->schema)->must;
5628 break;
5629 case LYS_LIST:
5630 must_size = ((struct lys_node_list *)node->schema)->must_size;
5631 must = ((struct lys_node_list *)node->schema)->must;
5632 break;
5633 case LYS_ANYXML:
5634 case LYS_ANYDATA:
5635 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5636 must = ((struct lys_node_anydata *)node->schema)->must;
5637 break;
5638 case LYS_NOTIF:
5639 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5640 must = ((struct lys_node_notif *)node->schema)->must;
5641 break;
5642 default:
5643 must_size = 0;
5644 break;
5645 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005646
5647 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005648 }
5649
5650 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005651 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005652 return -1;
5653 }
5654
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005655 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005656
Michal Vasko8146d4c2016-05-09 15:50:29 +02005657 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005658 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005659 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5660 } else {
5661 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5662 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005663 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005664 }
5665 if (must[i].eapptag) {
5666 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5667 }
5668 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005669 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005670 }
5671 }
5672
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005673 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005674}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005675
Michal Vaskobf19d252015-10-08 15:39:17 +02005676/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005677 * @brief Resolve (find) when condition schema context node. Does not log.
5678 *
5679 * @param[in] schema Schema node with the when condition.
5680 * @param[out] ctx_snode When schema context node.
5681 * @param[out] ctx_snode_type Schema context node type.
5682 */
5683void
5684resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5685{
5686 const struct lys_node *sparent;
5687
5688 /* find a not schema-only node */
5689 *ctx_snode_type = LYXP_NODE_ELEM;
5690 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5691 if (schema->nodetype == LYS_AUGMENT) {
5692 sparent = ((struct lys_node_augment *)schema)->target;
5693 } else {
5694 sparent = schema->parent;
5695 }
5696 if (!sparent) {
5697 /* context node is the document root (fake root in our case) */
5698 if (schema->flags & LYS_CONFIG_W) {
5699 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5700 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005701 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005702 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005703 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005704 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005705 break;
5706 }
5707 schema = sparent;
5708 }
5709
5710 *ctx_snode = (struct lys_node *)schema;
5711}
5712
5713/**
Michal Vaskocf024702015-10-08 15:01:42 +02005714 * @brief Resolve (find) when condition context node. Does not log.
5715 *
5716 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005717 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005718 * @param[out] ctx_node Context node.
5719 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005720 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005721 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005722 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005723static int
5724resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5725 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005726{
Michal Vaskocf024702015-10-08 15:01:42 +02005727 struct lyd_node *parent;
5728 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005729 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005730 uint16_t i, data_depth, schema_depth;
5731
Michal Vasko508a50d2016-09-07 14:50:33 +02005732 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005733
Michal Vaskofe989752016-09-08 08:47:26 +02005734 if (node_type == LYXP_NODE_ELEM) {
5735 /* standard element context node */
5736 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5737 for (sparent = schema, schema_depth = 0;
5738 sparent;
5739 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5740 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5741 ++schema_depth;
5742 }
Michal Vaskocf024702015-10-08 15:01:42 +02005743 }
Michal Vaskofe989752016-09-08 08:47:26 +02005744 if (data_depth < schema_depth) {
5745 return -1;
5746 }
Michal Vaskocf024702015-10-08 15:01:42 +02005747
Michal Vasko956e8542016-08-26 09:43:35 +02005748 /* find the corresponding data node */
5749 for (i = 0; i < data_depth - schema_depth; ++i) {
5750 node = node->parent;
5751 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005752 if (node->schema != schema) {
5753 return -1;
5754 }
Michal Vaskofe989752016-09-08 08:47:26 +02005755 } else {
5756 /* root context node */
5757 while (node->parent) {
5758 node = node->parent;
5759 }
5760 while (node->prev->next) {
5761 node = node->prev;
5762 }
Michal Vaskocf024702015-10-08 15:01:42 +02005763 }
5764
Michal Vaskoa59495d2016-08-22 09:18:58 +02005765 *ctx_node = node;
5766 *ctx_node_type = node_type;
5767 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005768}
5769
Michal Vasko76c3bd32016-08-24 16:02:52 +02005770/**
5771 * @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 +01005772 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005773 *
5774 * @param[in] snode Schema node, whose children instances need to be unlinked.
5775 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5776 * it is moved to point to another sibling still in the original tree.
5777 * @param[in,out] ctx_node When context node, adjusted if needed.
5778 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5779 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5780 * Ordering may change, but there will be no semantic change.
5781 *
5782 * @return EXIT_SUCCESS on success, -1 on error.
5783 */
5784static int
5785resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5786 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5787{
5788 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005789 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005790
5791 switch (snode->nodetype) {
5792 case LYS_AUGMENT:
5793 case LYS_USES:
5794 case LYS_CHOICE:
5795 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005796 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005797 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005798 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5799 continue;
5800 }
5801
5802 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005803 return -1;
5804 }
5805 }
5806 break;
5807 case LYS_CONTAINER:
5808 case LYS_LIST:
5809 case LYS_LEAF:
5810 case LYS_LEAFLIST:
5811 case LYS_ANYXML:
5812 case LYS_ANYDATA:
5813 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5814 if (elem->schema == snode) {
5815
5816 if (elem == *ctx_node) {
5817 /* We are going to unlink our context node! This normally cannot happen,
5818 * but we use normal top-level data nodes for faking a document root node,
5819 * so if this is the context node, we just use the next top-level node.
5820 * Additionally, it can even happen that there are no top-level data nodes left,
5821 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5822 * lyxp_eval() can handle this special situation.
5823 */
5824 if (ctx_node_type == LYXP_NODE_ELEM) {
5825 LOGINT;
5826 return -1;
5827 }
5828
5829 if (elem->prev == elem) {
5830 /* unlinking last top-level element, use an empty data tree */
5831 *ctx_node = NULL;
5832 } else {
5833 /* in this case just use the previous/last top-level data node */
5834 *ctx_node = elem->prev;
5835 }
5836 } else if (elem == *node) {
5837 /* We are going to unlink the currently processed node. This does not matter that
5838 * much, but we would lose access to the original data tree, so just move our
5839 * pointer somewhere still inside it.
5840 */
5841 if ((*node)->prev != *node) {
5842 *node = (*node)->prev;
5843 } else {
5844 /* the processed node with sibings were all unlinked, oh well */
5845 *node = NULL;
5846 }
5847 }
5848
5849 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005850 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005851 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005852 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005853 LOGINT;
5854 return -1;
5855 }
5856 } else {
5857 *unlinked_nodes = elem;
5858 }
5859
5860 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5861 /* there can be only one instance */
5862 break;
5863 }
5864 }
5865 }
5866 break;
5867 default:
5868 LOGINT;
5869 return -1;
5870 }
5871
5872 return EXIT_SUCCESS;
5873}
5874
5875/**
5876 * @brief Relink the unlinked nodes back.
5877 *
5878 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5879 * we simply need a sibling from the original data tree.
5880 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5881 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5882 * or the sibling of \p unlinked_nodes.
5883 *
5884 * @return EXIT_SUCCESS on success, -1 on error.
5885 */
5886static int
5887resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5888{
5889 struct lyd_node *elem;
5890
5891 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005892 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005893 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005894 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005895 return -1;
5896 }
5897 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005898 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005899 return -1;
5900 }
5901 }
5902 }
5903
5904 return EXIT_SUCCESS;
5905}
5906
Radek Krejci03b71f72016-03-16 11:10:09 +01005907int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005908resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005909{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005910 int ret = 0;
5911 uint8_t must_size;
5912 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005913
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005914 assert(node);
5915
5916 schema = node->schema;
5917
5918 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005919 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005920 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005921 must_size = ((struct lys_node_container *)schema)->must_size;
5922 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005923 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005924 must_size = ((struct lys_node_leaf *)schema)->must_size;
5925 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005926 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005927 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5928 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005929 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005930 must_size = ((struct lys_node_list *)schema)->must_size;
5931 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005932 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005933 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005934 must_size = ((struct lys_node_anydata *)schema)->must_size;
5935 break;
5936 case LYS_NOTIF:
5937 must_size = ((struct lys_node_notif *)schema)->must_size;
5938 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005939 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005940 must_size = 0;
5941 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005942 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005943
5944 if (must_size) {
5945 ++ret;
5946 }
5947
5948 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5949 if (!node->prev->next) {
5950 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5951 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5952 ret += 0x2;
5953 }
5954 }
5955
5956 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005957}
5958
5959int
Radek Krejci46165822016-08-26 14:06:27 +02005960resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005961{
Radek Krejci46165822016-08-26 14:06:27 +02005962 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005963
Radek Krejci46165822016-08-26 14:06:27 +02005964 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005965
Radek Krejci46165822016-08-26 14:06:27 +02005966 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005967 return 1;
5968 }
5969
Radek Krejci46165822016-08-26 14:06:27 +02005970 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005971 goto check_augment;
5972
Radek Krejci46165822016-08-26 14:06:27 +02005973 while (parent) {
5974 /* stop conditions */
5975 if (!mode) {
5976 /* stop on node that can be instantiated in data tree */
5977 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5978 break;
5979 }
5980 } else {
5981 /* stop on the specified node */
5982 if (parent == stop) {
5983 break;
5984 }
5985 }
5986
5987 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005988 return 1;
5989 }
5990check_augment:
5991
5992 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005993 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005994 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005995 }
5996 parent = lys_parent(parent);
5997 }
5998
5999 return 0;
6000}
6001
Michal Vaskocf024702015-10-08 15:01:42 +02006002/**
6003 * @brief Resolve (check) all when conditions relevant for \p node.
6004 * Logs directly.
6005 *
6006 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02006007 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006008 * @return
6009 * -1 - error, ly_errno is set
6010 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02006011 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01006012 * 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 +02006013 */
Radek Krejci46165822016-08-26 14:06:27 +02006014int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006015resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02006016{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006017 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006018 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006019 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006020 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02006021 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006022
6023 assert(node);
6024 memset(&set, 0, sizeof set);
6025
Michal Vasko78d97e22017-02-21 09:54:38 +01006026 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006027 /* make the node dummy for the evaluation */
6028 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006029 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6030 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006031 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006032 if (rc) {
6033 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006034 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006035 }
Radek Krejci51093642016-03-29 10:14:59 +02006036 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006037 }
6038
Radek Krejci03b71f72016-03-16 11:10:09 +01006039 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006040 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006041 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006042 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006043 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006044 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6045 ((struct lys_node_container *)node->schema)->when->cond);
6046 } else {
6047 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
6048 goto cleanup;
6049 }
Michal Vaskocf024702015-10-08 15:01:42 +02006050 }
Radek Krejci51093642016-03-29 10:14:59 +02006051
6052 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006053 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006054 }
6055
Michal Vasko90fc2a32016-08-24 15:58:58 +02006056 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006057 goto check_augment;
6058
6059 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006060 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6061 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006062 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006063 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006064 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006065 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006066 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006067 }
6068 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006069
6070 unlinked_nodes = NULL;
6071 /* we do not want our node pointer to change */
6072 tmp_node = node;
6073 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6074 if (rc) {
6075 goto cleanup;
6076 }
6077
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006078 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6079 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006080
6081 if (unlinked_nodes && ctx_node) {
6082 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6083 rc = -1;
6084 goto cleanup;
6085 }
6086 }
6087
Radek Krejci03b71f72016-03-16 11:10:09 +01006088 if (rc) {
6089 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006090 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006091 }
Radek Krejci51093642016-03-29 10:14:59 +02006092 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006093 }
6094
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006095 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006096 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006097 if ((ignore_fail == 1) || ((sparent->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_uses *)sparent)->when->cond);
6100 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006101 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006102 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6103 goto cleanup;
6104 }
Michal Vaskocf024702015-10-08 15:01:42 +02006105 }
Radek Krejci51093642016-03-29 10:14:59 +02006106
6107 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006108 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006109 }
6110
6111check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006112 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006113 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006114 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006115 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006116 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006117 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006118 }
6119 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006120
6121 unlinked_nodes = NULL;
6122 tmp_node = node;
6123 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6124 if (rc) {
6125 goto cleanup;
6126 }
6127
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006128 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6129 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006130
6131 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6132 * so the tree did not actually change and there is nothing for us to do
6133 */
6134 if (unlinked_nodes && ctx_node) {
6135 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6136 rc = -1;
6137 goto cleanup;
6138 }
6139 }
6140
Radek Krejci03b71f72016-03-16 11:10:09 +01006141 if (rc) {
6142 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006143 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006144 }
Radek Krejci51093642016-03-29 10:14:59 +02006145 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006146 }
6147
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006148 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006149 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006150 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006151 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006152 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006153 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006154 } else {
6155 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6156 goto cleanup;
6157 }
Michal Vaskocf024702015-10-08 15:01:42 +02006158 }
Radek Krejci51093642016-03-29 10:14:59 +02006159
6160 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006161 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006162 }
6163
Michal Vasko90fc2a32016-08-24 15:58:58 +02006164 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006165 }
6166
Radek Krejci0b7704f2016-03-18 12:16:14 +01006167 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006168
Radek Krejci51093642016-03-29 10:14:59 +02006169cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006170 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006171 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006172
Radek Krejci46165822016-08-26 14:06:27 +02006173 if (result) {
6174 if (node->when_status & LYD_WHEN_TRUE) {
6175 *result = 1;
6176 } else {
6177 *result = 0;
6178 }
6179 }
6180
Radek Krejci51093642016-03-29 10:14:59 +02006181 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006182}
6183
Radek Krejcicbb473e2016-09-16 14:48:32 +02006184static int
6185check_leafref_features(struct lys_type *type)
6186{
6187 struct lys_node *iter;
6188 struct ly_set *src_parents, *trg_parents, *features;
6189 unsigned int i, j, size, x;
6190 int ret = EXIT_SUCCESS;
6191
6192 assert(type->parent);
6193
6194 src_parents = ly_set_new();
6195 trg_parents = ly_set_new();
6196 features = ly_set_new();
6197
6198 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006199 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006200 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6201 continue;
6202 }
6203 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6204 }
6205 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006206 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006207 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6208 continue;
6209 }
6210 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6211 }
6212
6213 /* compare the features used in if-feature statements in the rest of both
6214 * chains of parents. The set of features used for target must be a subset
6215 * of features used for the leafref. This is not a perfect, we should compare
6216 * the truth tables but it could require too much resources, so we simplify that */
6217 for (i = 0; i < src_parents->number; i++) {
6218 iter = src_parents->set.s[i]; /* shortcut */
6219 if (!iter->iffeature_size) {
6220 continue;
6221 }
6222 for (j = 0; j < iter->iffeature_size; j++) {
6223 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6224 for (; size; size--) {
6225 if (!iter->iffeature[j].features[size - 1]) {
6226 /* not yet resolved feature, postpone this check */
6227 ret = EXIT_FAILURE;
6228 goto cleanup;
6229 }
6230 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6231 }
6232 }
6233 }
6234 x = features->number;
6235 for (i = 0; i < trg_parents->number; i++) {
6236 iter = trg_parents->set.s[i]; /* shortcut */
6237 if (!iter->iffeature_size) {
6238 continue;
6239 }
6240 for (j = 0; j < iter->iffeature_size; j++) {
6241 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6242 for (; size; size--) {
6243 if (!iter->iffeature[j].features[size - 1]) {
6244 /* not yet resolved feature, postpone this check */
6245 ret = EXIT_FAILURE;
6246 goto cleanup;
6247 }
6248 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6249 /* the feature is not present in features set of target's parents chain */
6250 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006251 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006252 "Leafref is not conditional based on \"%s\" feature as its target.",
6253 iter->iffeature[j].features[size - 1]->name);
6254 ret = -1;
6255 goto cleanup;
6256 }
6257 }
6258 }
6259 }
6260
6261cleanup:
6262 ly_set_free(features);
6263 ly_set_free(src_parents);
6264 ly_set_free(trg_parents);
6265
6266 return ret;
6267}
6268
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006269static int
6270check_type_union_leafref(struct lys_type *type)
6271{
6272 uint8_t i;
6273
6274 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6275 /* go through unions and look for leafref */
6276 for (i = 0; i < type->info.uni.count; ++i) {
6277 switch (type->info.uni.types[i].base) {
6278 case LY_TYPE_LEAFREF:
6279 return 1;
6280 case LY_TYPE_UNION:
6281 if (check_type_union_leafref(&type->info.uni.types[i])) {
6282 return 1;
6283 }
6284 break;
6285 default:
6286 break;
6287 }
6288 }
6289
6290 return 0;
6291 }
6292
6293 /* just inherit the flag value */
6294 return type->der->has_union_leafref;
6295}
6296
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006297/**
Michal Vaskobb211122015-08-19 14:03:11 +02006298 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006299 *
6300 * @param[in] mod Main module.
6301 * @param[in] item Item to resolve. Type determined by \p type.
6302 * @param[in] type Type of the unresolved item.
6303 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006304 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006305 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006306 *
6307 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6308 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006309static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006310resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006311 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006312{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006313 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006314 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006315 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006316 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006317 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006318 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006319
Radek Krejcic79c6b12016-07-26 15:11:49 +02006320 struct ly_set *refs, *procs;
6321 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006322 struct lys_ident *ident;
6323 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006324 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006325 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006326 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006327 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006328 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006329 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006330 struct lys_ext_instance *ext, **extlist;
6331 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006332
6333 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006334 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006335 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006336 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006337 ident = item;
6338
Radek Krejci018f1f52016-08-03 16:01:20 +02006339 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006340 break;
6341 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006342 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006343 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006344 stype = item;
6345
Radek Krejci018f1f52016-08-03 16:01:20 +02006346 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006347 break;
6348 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006349 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006350 stype = item;
6351
Michal Vasko1c007172017-03-10 10:20:44 +01006352 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6353 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006354 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006355 /* check if leafref and its target are under a common if-features */
6356 rc = check_leafref_features(stype);
6357 if (rc) {
6358 break;
6359 }
6360
Michal Vaskobb520442017-05-23 10:55:18 +02006361 if (lys_node_module(node)->implemented) {
6362 /* make all the modules on the path implemented */
6363 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6364 if (!lys_node_module(next)->implemented) {
6365 if (lys_set_implemented(lys_node_module(next))) {
6366 rc = -1;
6367 break;
6368 }
6369 }
6370 }
6371 if (next) {
6372 break;
6373 }
6374
6375 /* store the backlink from leafref target */
6376 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6377 rc = -1;
6378 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006379 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006380 }
6381
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006382 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006383 case UNRES_TYPE_DER_EXT:
6384 parent_type++;
6385 /* no break */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006386 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006387 parent_type++;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006388 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006389 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006390 /* parent */
6391 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006392 stype = item;
6393
Michal Vasko88c29542015-11-27 14:57:53 +01006394 /* HACK type->der is temporarily unparsed type statement */
6395 yin = (struct lyxml_elem *)stype->der;
6396 stype->der = NULL;
6397
Pavol Vicana0e4e672016-02-24 12:20:04 +01006398 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6399 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006400 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006401
6402 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006403 /* may try again later */
6404 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006405 } else {
6406 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006407 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006408 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006409 }
6410
Michal Vasko88c29542015-11-27 14:57:53 +01006411 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006412 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006413 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006414 /* we need to always be able to free this, it's safe only in this case */
6415 lyxml_free(mod->ctx, yin);
6416 } else {
6417 /* may try again later, put all back how it was */
6418 stype->der = (struct lys_tpdf *)yin;
6419 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006420 }
Radek Krejcic13db382016-08-16 10:52:42 +02006421 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006422 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006423 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006424 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6425 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006426
6427 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6428 /* fill typedef union leafref flag */
6429 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6430 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6431 /* copy the type in case it has union leafref flag */
6432 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
6433 LOGERR(LY_EINT, "Failed to duplicate type.");
6434 return -1;
6435 }
6436 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006437 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006438 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6439 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6440 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6441 * 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 +02006442 * 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 +02006443 * of the type's base member. */
6444 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6445 if (par_grp) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01006446#if __BYTE_ORDER == __LITTLE_ENDIAN
6447 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
6448#else
6449 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
6450#endif
Radek Krejci9b6aad22016-09-20 15:55:51 +02006451 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006452 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006453 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006455 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006456 iff_data = str_snode;
6457 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006458 if (!rc) {
6459 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006460 if (iff_data->infeature) {
6461 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6462 feat = *((struct lys_feature **)item);
6463 if (!feat->depfeatures) {
6464 feat->depfeatures = ly_set_new();
6465 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006466 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006467 }
6468 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006469 lydict_remove(mod->ctx, iff_data->fname);
6470 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006471 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006472 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006473 case UNRES_FEATURE:
6474 feat = (struct lys_feature *)item;
6475
6476 if (feat->iffeature_size) {
6477 refs = ly_set_new();
6478 procs = ly_set_new();
6479 ly_set_add(procs, feat, 0);
6480
6481 while (procs->number) {
6482 ref = procs->set.g[procs->number - 1];
6483 ly_set_rm_index(procs, procs->number - 1);
6484
6485 for (i = 0; i < ref->iffeature_size; i++) {
6486 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6487 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006488 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006489 if (ref->iffeature[i].features[j - 1] == feat) {
6490 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6491 goto featurecheckdone;
6492 }
6493
6494 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6495 k = refs->number;
6496 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6497 /* not yet seen feature, add it for processing */
6498 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6499 }
6500 }
6501 } else {
6502 /* forward reference */
6503 rc = EXIT_FAILURE;
6504 goto featurecheckdone;
6505 }
6506 }
6507
6508 }
6509 }
6510 rc = EXIT_SUCCESS;
6511
6512featurecheckdone:
6513 ly_set_free(refs);
6514 ly_set_free(procs);
6515 }
6516
6517 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006518 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006519 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006520 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006521 case UNRES_TYPEDEF_DFLT:
6522 parent_type++;
6523 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006524 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006525 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006526 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006527 break;
6528 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006529 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006530 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006531 choic = item;
6532
Radek Krejcie00d2312016-08-12 15:27:49 +02006533 if (!choic->dflt) {
6534 choic->dflt = resolve_choice_dflt(choic, expr);
6535 }
Michal Vasko7955b362015-09-04 14:18:15 +02006536 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006537 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006538 } else {
6539 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006540 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006541 break;
6542 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006543 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006544 break;
6545 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006546 unique_info = (struct unres_list_uniq *)item;
6547 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006548 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006549 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006550 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006551 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006552 case UNRES_XPATH:
6553 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006554 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006555 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006556 case UNRES_EXT:
6557 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006558 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006559 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006560 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006561 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006562 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006563 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006564 if (eplugin) {
6565 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006566 u = malloc(sizeof *u);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006567 LY_CHECK_ERR_RETURN(!u, LOGMEM, -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006568 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006569 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6570 /* something really bad happend since the extension finalization is not actually
6571 * being resolved while adding into unres, so something more serious with the unres
6572 * list itself must happened */
6573 return -1;
6574 }
Radek Krejci80056d52017-01-05 13:13:33 +01006575 }
6576 }
Radek Krejci79685c92017-02-17 10:49:43 +01006577 }
6578 if (!rc || rc == -1) {
6579 /* cleanup on success or fatal error */
6580 if (ext_data->datatype == LYS_IN_YIN) {
6581 /* YIN */
6582 lyxml_free(mod->ctx, ext_data->data.yin);
6583 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006584 /* YANG */
6585 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006586 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006587 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006588 }
6589 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006590 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006591 u = (uint8_t *)str_snode;
6592 ext = (*(struct lys_ext_instance ***)item)[*u];
6593 free(u);
6594
Radek Krejci80056d52017-01-05 13:13:33 +01006595 eplugin = ext->def->plugin;
6596
6597 /* inherit */
6598 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6599 root = (struct lys_node *)ext->parent;
6600 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6601 LY_TREE_DFS_BEGIN(root->child, next, node) {
6602 /* first, check if the node already contain instance of the same extension,
6603 * in such a case we won't inherit. In case the node was actually defined as
6604 * augment data, we are supposed to check the same way also the augment node itself */
6605 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6606 goto inherit_dfs_sibling;
6607 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6608 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6609 goto inherit_dfs_sibling;
6610 }
6611
6612 if (eplugin->check_inherit) {
6613 /* we have a callback to check the inheritance, use it */
6614 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6615 case 0:
6616 /* yes - continue with the inheriting code */
6617 break;
6618 case 1:
6619 /* no - continue with the node's sibling */
6620 goto inherit_dfs_sibling;
6621 case 2:
6622 /* no, but continue with the children, just skip the inheriting code for this node */
6623 goto inherit_dfs_child;
6624 default:
6625 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6626 ext->def->module->name, ext->def->name, rc);
6627 }
6628 }
6629
6630 /* inherit the extension */
6631 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006632 LY_CHECK_ERR_RETURN(!extlist, LOGMEM, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006633 extlist[node->ext_size] = malloc(sizeof **extlist);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006634 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM; node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006635 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6636 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6637
6638 node->ext = extlist;
6639 node->ext_size++;
6640
6641inherit_dfs_child:
6642 /* modification of - select element for the next run - children first */
6643 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6644 next = NULL;
6645 } else {
6646 next = node->child;
6647 }
6648 if (!next) {
6649inherit_dfs_sibling:
6650 /* no children, try siblings */
6651 next = node->next;
6652 }
6653 while (!next) {
6654 /* go to the parent */
6655 node = lys_parent(node);
6656
6657 /* we are done if we are back in the root (the starter's parent */
6658 if (node == root) {
6659 break;
6660 }
6661
6662 /* parent is already processed, go to its sibling */
6663 next = node->next;
6664 }
6665 }
6666 }
6667 }
6668
6669 /* final check */
6670 if (eplugin->check_result) {
6671 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006672 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006673 return -1;
6674 }
6675 }
6676
6677 rc = 0;
6678 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006679 default:
6680 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006681 break;
6682 }
6683
Radek Krejci54081ce2016-08-12 15:21:47 +02006684 if (has_str && !rc) {
6685 /* the string is no more needed in case of success.
6686 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006687 lydict_remove(mod->ctx, str_snode);
6688 }
6689
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006690 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006691}
6692
Michal Vaskof02e3742015-08-05 16:27:02 +02006693/* logs directly */
6694static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006695print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006696{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006697 struct lyxml_elem *xml;
6698 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006699 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006700 const char *name = NULL;
6701 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006702
Michal Vaskof02e3742015-08-05 16:27:02 +02006703 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006704 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006705 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006706 break;
6707 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006708 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006709 break;
6710 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006711 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6712 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006713 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006714 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006715 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006716 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006717 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6718 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006719 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006720 } else {
6721 LY_TREE_FOR(xml->attr, attr) {
6722 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006723 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006724 break;
6725 }
6726 }
6727 assert(attr);
6728 }
Radek Krejcie534c132016-11-23 13:32:31 +01006729 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006730 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006731 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006732 iff_data = str_node;
6733 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006734 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006735 case UNRES_FEATURE:
6736 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6737 ((struct lys_feature *)item)->name);
6738 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006739 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006740 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006741 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006742 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006743 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006744 if (str_node) {
6745 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6746 } /* else no default value in the type itself, but we are checking some restrictions against
6747 * possible default value of some base type. The failure is caused by not resolved base type,
6748 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006749 break;
6750 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006751 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006752 break;
6753 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006754 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006755 break;
6756 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006757 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006758 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006759 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006760 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6761 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006762 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006763 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006764 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6765 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006766 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006767 case UNRES_EXT:
6768 extinfo = (struct unres_ext *)str_node;
6769 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6770 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6771 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006772 default:
6773 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006774 break;
6775 }
6776}
6777
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006778/**
Michal Vaskobb211122015-08-19 14:03:11 +02006779 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006780 *
6781 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006782 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006783 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006784 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006785 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006786int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006787resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006788{
Radek Krejci010e54b2016-03-15 09:40:34 +01006789 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006790 struct lyxml_elem *yin;
6791 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006792 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006793
6794 assert(unres);
6795
Michal Vaskoe8734262016-09-29 14:12:06 +02006796 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006797 if (*ly_vlog_hide_location()) {
6798 log_hidden = 1;
6799 } else {
6800 log_hidden = 0;
6801 ly_vlog_hide(1);
6802 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006803
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006804 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006805 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006806 unres_count = 0;
6807 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006808
6809 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006810 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006811 * if-features are resolved here to make sure that we will have all if-features for
6812 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006813 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006814 continue;
6815 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006816 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006817 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006818
Michal Vasko88c29542015-11-27 14:57:53 +01006819 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006820 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006821 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006822 unres->type[i] = UNRES_RESOLVED;
6823 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006824 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006825 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006826 if (!log_hidden) {
6827 ly_vlog_hide(0);
6828 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006829 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006830 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006831 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006832 } else {
6833 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006834 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006835 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006836 }
Michal Vasko88c29542015-11-27 14:57:53 +01006837 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006838
Michal Vasko88c29542015-11-27 14:57:53 +01006839 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006840 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006841 if (!log_hidden) {
6842 ly_vlog_hide(0);
6843 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006844
6845 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006846 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006847 continue;
6848 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006849 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejci63fc0962017-02-15 13:20:18 +01006850 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006851 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6852 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6853 yang =(struct yang_type *)yin;
6854 ((struct lys_type *)unres->item[i])->base = yang->base;
6855 if (yang->base == LY_TYPE_UNION) {
6856 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6857 }
6858 lydict_remove(mod->ctx, yang->name);
6859 free(yang);
6860 } else {
6861 lyxml_free(mod->ctx, yin);
6862 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006863 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006864 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006865 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006866 }
6867
Radek Krejci07d0fb92017-01-13 14:11:05 +01006868 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006869 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006870 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006871 continue;
6872 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006873
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006874 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006875 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006876 if (unres->type[i] == UNRES_LIST_UNIQ) {
6877 /* free the allocated structure */
6878 free(unres->item[i]);
6879 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006880 unres->type[i] = UNRES_RESOLVED;
6881 ++resolved;
6882 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006883 if (!log_hidden) {
6884 ly_vlog_hide(0);
6885 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006886 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006887 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006888 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006889 } else {
6890 /* forward reference, erase ly_errno */
6891 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006892 }
6893 }
6894
Michal Vasko74a60c02017-03-08 10:19:48 +01006895 if (!log_hidden) {
6896 ly_vlog_hide(0);
6897 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006898
Radek Krejci80056d52017-01-05 13:13:33 +01006899 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6900 for (i = 0; i < unres->count; ++i) {
6901 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6902 continue;
6903 }
6904
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006905 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci791f6c72017-02-22 15:23:39 +01006906 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006907 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006908 ++resolved;
6909 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006910 /* else error - it was already printed, but resolved was not increased,
6911 so this unres item will not be resolved again in the following code,
6912 but it will cause returning -1 at the end, this way we are able to
6913 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006914 }
6915
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006916 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006917 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6918 * all the validation errors
6919 */
6920 for (i = 0; i < unres->count; ++i) {
6921 if (unres->type[i] == UNRES_RESOLVED) {
6922 continue;
6923 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006924 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006925 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006926 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006927 unres->type[i] = UNRES_RESOLVED;
6928 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006929 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006930 }
Radek Krejcib3142312016-11-09 11:04:12 +01006931 if (resolved < unres->count) {
6932 return -1;
6933 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006934 }
6935
Michal Vaskoe8734262016-09-29 14:12:06 +02006936 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006937 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006938 return EXIT_SUCCESS;
6939}
6940
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006941/**
Michal Vaskobb211122015-08-19 14:03:11 +02006942 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006943 *
6944 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006945 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006946 * @param[in] item Item to resolve. Type determined by \p type.
6947 * @param[in] type Type of the unresolved item.
6948 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006949 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006950 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006951 */
6952int
Radek Krejci48464ed2016-03-17 15:44:09 +01006953unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6954 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006955{
Radek Krejci54081ce2016-08-12 15:21:47 +02006956 int rc;
6957 const char *dictstr;
6958
6959 dictstr = lydict_insert(mod->ctx, str, 0);
6960 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6961
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006962 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006963 lydict_remove(mod->ctx, dictstr);
6964 }
6965 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006966}
6967
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006968/**
Michal Vaskobb211122015-08-19 14:03:11 +02006969 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006970 *
6971 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006972 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006973 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006974 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006975 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006976 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006977 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6978 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006979 */
6980int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006981unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006982 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006983{
Michal Vaskoef486d72016-09-27 12:10:44 +02006984 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006985 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006986
Michal Vasko9bf425b2015-10-22 11:42:03 +02006987 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6988 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006989
Michal Vasko9e862e82017-03-08 10:20:49 +01006990#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006991 uint32_t u;
6992
Radek Krejci850a5de2016-11-08 14:06:40 +01006993 /* check for duplicities in unres */
6994 for (u = 0; u < unres->count; u++) {
6995 if (unres->type[u] == type && unres->item[u] == item &&
6996 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006997 /* duplication, should not happen */
6998 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006999 }
7000 }
Michal Vasko9e862e82017-03-08 10:20:49 +01007001#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01007002
Radek Krejcic293bac2017-02-27 11:25:28 +01007003 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01007004 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01007005 rc = EXIT_FAILURE;
7006 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01007007 if (*ly_vlog_hide_location()) {
7008 log_hidden = 1;
7009 } else {
7010 log_hidden = 0;
7011 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007012 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01007013 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01007014 if (!log_hidden) {
7015 ly_vlog_hide(0);
7016 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007017
Radek Krejci80056d52017-01-05 13:13:33 +01007018 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02007019 if (rc == -1) {
Radek Krejci80056d52017-01-05 13:13:33 +01007020 ly_err_repeat();
7021 }
7022 if (type == UNRES_LIST_UNIQ) {
7023 /* free the allocated structure */
7024 free(item);
7025 } else if (rc == -1 && type == UNRES_IFFEAT) {
7026 /* free the allocated resources */
7027 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007028 }
Radek Krejci80056d52017-01-05 13:13:33 +01007029 return rc;
7030 } else {
7031 /* erase info about validation errors */
7032 ly_err_clean(1);
7033 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007034
Radek Krejci80056d52017-01-05 13:13:33 +01007035 print_unres_schema_item_fail(item, type, snode);
7036
7037 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7038 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7039 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7040 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7041 lyxml_unlink_elem(mod->ctx, yin, 1);
7042 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7043 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007044 }
Michal Vasko88c29542015-11-27 14:57:53 +01007045 }
7046
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007047 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007048 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007049 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007050 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007051 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007052 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007053 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007054 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007055 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM, -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007056 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007057 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007058 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM, -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007059 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);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007108 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM, -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007109 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7110 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7111 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7112 LOGINT;
7113 return -1;
7114 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007115 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007116 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007117 LOGINT;
7118 return -1;
7119 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007120 }
Michal Vaskodad19402015-08-06 09:51:53 +02007121
7122 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007123}
7124
Michal Vaskof02e3742015-08-05 16:27:02 +02007125/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007126int
Michal Vasko878e38d2016-09-05 12:17:53 +02007127unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007128{
Michal Vasko878e38d2016-09-05 12:17:53 +02007129 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007130 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007131
Radek Krejciddddd0d2017-01-20 15:20:46 +01007132 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007133 i = start_on_backwards;
7134 } else {
7135 i = unres->count - 1;
7136 }
7137 for (; i > -1; i--) {
7138 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007139 continue;
7140 }
7141 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007142 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007143 break;
7144 }
7145 } else {
7146 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7147 aux_uniq2 = (struct unres_list_uniq *)item;
7148 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007149 break;
7150 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007151 }
7152 }
7153
Michal Vasko878e38d2016-09-05 12:17:53 +02007154 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007155}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007156
Michal Vaskoede9c472016-06-07 09:38:15 +02007157static void
7158unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7159{
7160 struct lyxml_elem *yin;
7161 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007162 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007163
7164 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007165 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007166 case UNRES_TYPE_DER:
7167 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7168 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7169 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007170 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007171 lydict_remove(ctx, yang->name);
7172 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007173 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7174 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7175 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007176 } else {
7177 lyxml_free(ctx, yin);
7178 }
7179 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007180 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007181 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7182 lydict_remove(ctx, iff_data->fname);
7183 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007184 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007185 case UNRES_IDENT:
7186 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007187 case UNRES_CHOICE_DFLT:
7188 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007189 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7190 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007191 case UNRES_LIST_UNIQ:
7192 free(unres->item[i]);
7193 break;
PavolVicanc1807262017-01-31 18:00:27 +01007194 case UNRES_EXT:
7195 free(unres->str_snode[i]);
7196 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007197 default:
7198 break;
7199 }
7200 unres->type[i] = UNRES_RESOLVED;
7201}
7202
Michal Vasko88c29542015-11-27 14:57:53 +01007203void
Michal Vasko44ab1462017-05-18 13:18:36 +02007204unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007205{
7206 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007207 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007208
Radek Krejcic071c542016-01-27 14:57:51 +01007209 if (!unres || !(*unres)) {
7210 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007211 }
7212
Michal Vasko44ab1462017-05-18 13:18:36 +02007213 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007214
7215 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007216 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007217 if ((*unres)->type[i] != UNRES_RESOLVED) {
7218 unresolved++;
7219 }
7220 continue;
7221 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007222
7223 /* free heap memory for the specific item */
7224 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007225 }
7226
Michal Vaskoede9c472016-06-07 09:38:15 +02007227 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007228 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007229 free((*unres)->item);
7230 free((*unres)->type);
7231 free((*unres)->str_snode);
7232 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007233 free((*unres));
7234 (*unres) = NULL;
7235 }
Michal Vasko88c29542015-11-27 14:57:53 +01007236}
7237
Michal Vasko3cfa3182017-01-17 10:00:58 +01007238static int
7239check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7240{
7241 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007242 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007243 char *buf;
7244
7245 for (op_node = lys_parent(sleaf);
7246 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7247 op_node = lys_parent(op_node));
7248
7249 if (op_node && lys_parent(op_node)) {
7250 /* nested operation - any absolute path is external */
7251 return 1;
7252 }
7253
7254 /* get the first node from the instid */
7255 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7256 if (!buf) {
7257 LOGMEM;
7258 return -1;
7259 }
7260
7261 /* there is a predicate, remove it */
7262 if (buf[strlen(buf) - 1] == ']') {
7263 assert(strchr(buf, '['));
7264 *strchr(buf, '[') = '\0';
7265 }
7266
7267 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01007268 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007269 if (!set || !set->number) {
7270 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007271 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007272 return 1;
7273 }
7274 free(buf);
7275
Michal Vasko3c777092017-01-17 14:10:09 +01007276 first_node = set->set.s[0];
7277 ly_set_free(set);
7278
Michal Vasko3cfa3182017-01-17 10:00:58 +01007279 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7280
7281 if (op_node) {
7282 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007283 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007284 assert(set->number == 1);
7285 return 0;
7286 } else {
7287 return 1;
7288 }
7289 }
7290
7291 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7292 * this itself), so we say it's not external */
7293 return 0;
7294}
7295
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007296/**
7297 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7298 *
7299 * @param[in] data Data node where the path is used
7300 * @param[in] path Instance-identifier node value.
7301 * @param[in,out] ret Resolved instance or NULL.
7302 *
7303 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7304 */
7305static int
7306resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7307{
7308 int i = 0, j;
7309 const struct lys_module *mod;
7310 struct ly_ctx *ctx = data->schema->module->ctx;
7311 const char *model, *name;
7312 char *str;
7313 int mod_len, name_len, has_predicate;
7314 struct unres_data node_match;
7315
7316 memset(&node_match, 0, sizeof node_match);
7317 *ret = NULL;
7318
7319 /* we need root to resolve absolute path */
7320 for (; data->parent; data = data->parent);
7321 /* we're still parsing it and the pointer is not correct yet */
7322 if (data->prev) {
7323 for (; data->prev->next; data = data->prev);
7324 }
7325
7326 /* search for the instance node */
7327 while (path[i]) {
7328 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7329 if (j <= 0) {
7330 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7331 goto error;
7332 }
7333 i += j;
7334
7335 str = strndup(model, mod_len);
7336 if (!str) {
7337 LOGMEM;
7338 goto error;
7339 }
7340 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007341 if (ctx->data_clb) {
7342 if (!mod) {
7343 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7344 } else if (!mod->implemented) {
7345 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7346 }
7347 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007348 free(str);
7349
Michal Vaskof53187d2017-01-13 13:23:14 +01007350 if (!mod || !mod->implemented || mod->disabled) {
7351 break;
7352 }
7353
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007354 if (resolve_data(mod, name, name_len, data, &node_match)) {
7355 /* no instance exists */
7356 break;
7357 }
7358
7359 if (has_predicate) {
7360 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1c007172017-03-10 10:20:44 +01007361 j = resolve_instid_predicate(&path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007362 if (j < 1) {
7363 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7364 goto error;
7365 }
7366 i += j;
7367
7368 if (!node_match.count) {
7369 /* no instance exists */
7370 break;
7371 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007372 } else if (node_match.count) {
7373 /* check that we are not addressing lists */
7374 for (j = 0; (unsigned)j < node_match.count; ++j) {
7375 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7376 unres_data_del(&node_match, j--);
7377 }
7378 }
7379 if (!node_match.count) {
7380 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7381 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007382 }
7383 }
7384
7385 if (!node_match.count) {
7386 /* no instance exists */
7387 if (req_inst > -1) {
7388 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7389 return EXIT_FAILURE;
7390 }
7391 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7392 return EXIT_SUCCESS;
7393 } else if (node_match.count > 1) {
7394 /* instance identifier must resolve to a single node */
7395 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7396 goto error;
7397 } else {
7398 /* we have required result, remember it and cleanup */
7399 *ret = node_match.node[0];
7400 free(node_match.node);
7401 return EXIT_SUCCESS;
7402 }
7403
7404error:
7405 /* cleanup */
7406 free(node_match.node);
7407 return -1;
7408}
7409
7410static int
7411resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007412{
Radek Krejci7de36cf2016-09-12 16:18:50 +02007413 struct unres_data matches;
7414 uint32_t i;
7415
Radek Krejci9b6aad22016-09-20 15:55:51 +02007416 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007417 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007418 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007419
7420 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007421 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007422 return -1;
7423 }
7424
7425 /* check that value matches */
7426 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007427 /* not that the value is already in canonical form since the parsers does the conversion,
7428 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007429 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007430 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007431 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007432 break;
7433 }
7434 }
7435
7436 free(matches.node);
7437
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007438 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007439 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007440 if (req_inst > -1) {
7441 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007442 return EXIT_FAILURE;
7443 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007444 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 +02007445 }
7446 }
7447
7448 return EXIT_SUCCESS;
7449}
7450
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007451/* 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 +01007452int
7453resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7454 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007455{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007456 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007457 struct lyd_node *ret;
7458 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007459 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007460
7461 assert(type->base == LY_TYPE_UNION);
7462
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007463 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7464 /* either NULL or instid previously converted to JSON */
7465 json_val = leaf->value.string;
7466 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007467
Michal Vaskofd6c6502017-01-06 12:15:41 +01007468 if (store) {
7469 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7470 free(leaf->value.bit);
7471 }
7472 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007473 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007474
7475 /* turn logging off, we are going to try to validate the value with all the types in order */
7476 hidden = *ly_vlog_hide_location();
7477 ly_vlog_hide(1);
7478
7479 t = NULL;
7480 found = 0;
7481 while ((t = lyp_get_next_union_type(type, t, &found))) {
7482 found = 0;
7483
7484 switch (t->base) {
7485 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007486 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7487 req_inst = -1;
7488 } else {
7489 req_inst = t->info.lref.req;
7490 }
7491
7492 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007493 if (store) {
7494 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7495 /* valid resolved */
7496 leaf->value.leafref = ret;
7497 leaf->value_type = LY_TYPE_LEAFREF;
7498 } else {
7499 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007500 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007501 return -1;
7502 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007503 }
7504 }
7505
7506 success = 1;
7507 }
7508 break;
7509 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007510 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7511 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7512 req_inst = -1;
7513 } else {
7514 req_inst = t->info.inst.req;
7515 }
7516
Michal Vaskod3a03112017-01-23 09:56:02 +01007517 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007518 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007519 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007520 /* valid resolved */
7521 leaf->value.instance = ret;
7522 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007523
Michal Vaskofd6c6502017-01-06 12:15:41 +01007524 if (json_val) {
7525 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7526 leaf->value_str = json_val;
7527 json_val = NULL;
7528 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007529 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007530 /* valid unresolved */
7531 if (json_val) {
7532 /* put the JSON val back */
7533 leaf->value.string = json_val;
7534 json_val = NULL;
7535 } else {
7536 leaf->value.instance = NULL;
7537 }
7538 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007539 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007540 }
7541
7542 success = 1;
7543 }
7544 break;
7545 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007546 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007547 success = 1;
7548 }
7549 break;
7550 }
7551
7552 if (success) {
7553 break;
7554 }
7555
7556 /* erase information about errors - they are false or irrelevant
7557 * and will be replaced by a single error messages */
7558 ly_err_clean(1);
7559
7560 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007561 if (store) {
7562 if (t->base == LY_TYPE_BITS) {
7563 free(leaf->value.bit);
7564 }
7565 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007566 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007567 }
7568
7569 /* turn logging back on */
7570 if (!hidden) {
7571 ly_vlog_hide(0);
7572 }
7573
7574 if (json_val) {
7575 if (!success) {
7576 /* put the value back for now */
7577 assert(leaf->value_type == LY_TYPE_UNION);
7578 leaf->value.string = json_val;
7579 } else {
7580 /* value was ultimately useless, but we could not have known */
7581 lydict_remove(leaf->schema->module->ctx, json_val);
7582 }
7583 }
7584
Michal Vaskofd6c6502017-01-06 12:15:41 +01007585 if (success) {
7586 if (resolved_type) {
7587 *resolved_type = t;
7588 }
7589 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007590 /* not found and it is required */
7591 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007592 return EXIT_FAILURE;
7593 }
7594
7595 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007596
Radek Krejci9b6aad22016-09-20 15:55:51 +02007597}
7598
Michal Vasko8bcdf292015-08-19 14:04:43 +02007599/**
7600 * @brief Resolve a single unres data item. Logs directly.
7601 *
Michal Vaskocf024702015-10-08 15:01:42 +02007602 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007603 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007604 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007605 *
7606 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7607 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007608int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007609resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007610{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007611 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007612 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007613 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007614 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007615
Michal Vasko83a6c462015-10-08 16:43:53 +02007616 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007617 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007618
Michal Vaskocf024702015-10-08 15:01:42 +02007619 switch (type) {
7620 case UNRES_LEAFREF:
7621 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007622 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007623 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7624 req_inst = -1;
7625 } else {
7626 req_inst = sleaf->type.info.lref.req;
7627 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007628 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7629 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007630 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007631 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007632 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7633 free(leaf->value.bit);
7634 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007635 leaf->value.leafref = ret;
7636 leaf->value_type = LY_TYPE_LEAFREF;
7637 } else {
7638 /* valid unresolved */
7639 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007640 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007641 return -1;
7642 }
7643 }
7644 }
7645 leaf->validity &= ~LYD_VAL_LEAFREF;
7646 } else {
7647 return rc;
7648 }
7649 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007650
Michal Vaskocf024702015-10-08 15:01:42 +02007651 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007652 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007653 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7654 if (ext_dep == -1) {
7655 return -1;
7656 }
7657
7658 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7659 req_inst = -1;
7660 } else {
7661 req_inst = sleaf->type.info.inst.req;
7662 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007663 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7664 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007665 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007666 /* valid resolved */
7667 leaf->value.instance = ret;
7668 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007669 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007670 /* valid unresolved */
7671 leaf->value.instance = NULL;
7672 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007673 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007674 } else {
7675 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007676 }
Michal Vaskocf024702015-10-08 15:01:42 +02007677 break;
7678
Radek Krejci7de36cf2016-09-12 16:18:50 +02007679 case UNRES_UNION:
7680 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007681 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007682
Michal Vaskocf024702015-10-08 15:01:42 +02007683 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007684 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007685 return rc;
7686 }
7687 break;
7688
Michal Vaskobf19d252015-10-08 15:39:17 +02007689 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007690 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007691 return rc;
7692 }
7693 break;
7694
7695 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007696 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007697 return rc;
7698 }
7699 break;
7700
Michal Vaskocf024702015-10-08 15:01:42 +02007701 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007702 LOGINT;
7703 return -1;
7704 }
7705
7706 return EXIT_SUCCESS;
7707}
7708
7709/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007710 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007711 *
7712 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007713 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007714 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007715 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007716 */
7717int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007718unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007719{
Radek Krejci03b71f72016-03-16 11:10:09 +01007720 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007721 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007722 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007723
Radek Krejci03b71f72016-03-16 11:10:09 +01007724 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007725 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007726 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007727 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007728 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007729 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007730 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007731
Radek Krejci0b7704f2016-03-18 12:16:14 +01007732 if (type == UNRES_WHEN) {
7733 /* remove previous result */
7734 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007735 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007736
7737 return EXIT_SUCCESS;
7738}
7739
7740/**
7741 * @brief Resolve every unres data item in the structure. Logs directly.
7742 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007743 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7744 * unresolved leafrefs/instids are accepted).
7745 *
7746 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7747 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007748 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007749 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7750 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007751 *
7752 * @return EXIT_SUCCESS on success, -1 on error.
7753 */
7754int
Radek Krejci082c84f2016-10-17 16:33:06 +02007755resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007756{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007757 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007758 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007759 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007760
Radek Krejci082c84f2016-10-17 16:33:06 +02007761 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007762 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007763
7764 if (!unres->count) {
7765 return EXIT_SUCCESS;
7766 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007767
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007768 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 +01007769 ignore_fail = 1;
7770 } else if (options & LYD_OPT_NOEXTDEPS) {
7771 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007772 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007773 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007774 }
7775
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007776 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007777 ly_vlog_hide(1);
7778
Radek Krejci0b7704f2016-03-18 12:16:14 +01007779 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007780 first = 1;
7781 stmt_count = 0;
7782 resolved = 0;
7783 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007784 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007785 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007786 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007787 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007788 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007789 continue;
7790 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007791 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007792 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007793 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007794 }
7795
7796 /* resolve when condition only when all parent when conditions are already resolved */
7797 for (parent = unres->node[i]->parent;
7798 parent && LYD_WHEN_DONE(parent->when_status);
7799 parent = parent->parent) {
7800 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7801 /* the parent node was already unlinked, do not resolve this node,
7802 * it will be removed anyway, so just mark it as resolved
7803 */
7804 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7805 unres->type[i] = UNRES_RESOLVED;
7806 resolved++;
7807 break;
7808 }
7809 }
7810 if (parent) {
7811 continue;
7812 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007813
Michal Vasko3cfa3182017-01-17 10:00:58 +01007814 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007815 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007816 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007817 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007818 /* false when condition */
7819 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007820 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007821 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007822 } /* follows else */
7823
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007824 /* auto-delete */
7825 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7826 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7827
Radek Krejci0c0086a2016-03-24 15:20:28 +01007828 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7829 /* if it has parent non-presence containers that would be empty, we should actually
7830 * remove the container
7831 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007832 for (parent = unres->node[i];
7833 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7834 parent = parent->parent) {
7835 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7836 /* presence container */
7837 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007838 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007839 if (parent->next || parent->prev != parent) {
7840 /* non empty (the child we are in and we are going to remove is not the only child) */
7841 break;
7842 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007843 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007844 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007845
Radek Krejci0c0086a2016-03-24 15:20:28 +01007846 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007847 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007848 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007849
Radek Krejci0b7704f2016-03-18 12:16:14 +01007850 lyd_unlink(unres->node[i]);
7851 unres->type[i] = UNRES_DELETE;
7852 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007853
7854 /* update the rest of unres items */
7855 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007856 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007857 continue;
7858 }
7859
7860 /* test if the node is in subtree to be deleted */
7861 for (parent = unres->node[j]; parent; parent = parent->parent) {
7862 if (parent == unres->node[i]) {
7863 /* yes, it is */
7864 unres->type[j] = UNRES_RESOLVED;
7865 resolved++;
7866 break;
7867 }
7868 }
7869 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007870 } else {
7871 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007872 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007873 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007874 resolved++;
7875 progress = 1;
7876 } else if (rc == -1) {
7877 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007878 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007879 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007880 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007881 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007882 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007883 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007884 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007885
Radek Krejci0b7704f2016-03-18 12:16:14 +01007886 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007887 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007888 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007889 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007890 return -1;
7891 }
7892
7893 for (i = 0; del_items && i < unres->count; i++) {
7894 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7895 if (unres->type[i] != UNRES_DELETE) {
7896 continue;
7897 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007898 if (!unres->node[i]) {
7899 unres->type[i] = UNRES_RESOLVED;
7900 del_items--;
7901 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007902 }
7903
7904 /* really remove the complete subtree */
7905 lyd_free(unres->node[i]);
7906 unres->type[i] = UNRES_RESOLVED;
7907 del_items--;
7908 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007909
7910 /* now leafrefs */
7911 first = 1;
7912 stmt_count = 0;
7913 resolved = 0;
7914 do {
7915 progress = 0;
7916 for (i = 0; i < unres->count; i++) {
7917 if (unres->type[i] != UNRES_LEAFREF) {
7918 continue;
7919 }
7920 if (first) {
7921 /* count leafref nodes in unres list */
7922 stmt_count++;
7923 }
7924
7925 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7926 if (!rc) {
7927 unres->type[i] = UNRES_RESOLVED;
7928 ly_err_clean(1);
7929 resolved++;
7930 progress = 1;
7931 } else if (rc == -1) {
7932 ly_vlog_hide(0);
7933 /* print only this last error */
7934 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7935 return -1;
7936 } /* else forward reference */
7937 }
7938 first = 0;
7939 } while (progress && resolved < stmt_count);
7940
7941 /* do we have some unresolved leafrefs? */
7942 if (stmt_count > resolved) {
7943 ly_vlog_hide(0);
7944 ly_err_repeat();
7945 return -1;
7946 }
7947
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007948 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007949
7950 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007951 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007952 if (unres->type[i] == UNRES_RESOLVED) {
7953 continue;
7954 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007955 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007956
Michal Vasko3cfa3182017-01-17 10:00:58 +01007957 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007958 if (rc) {
7959 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007960 return -1;
7961 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007962
7963 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007964 }
7965
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007966 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007967 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007968 return EXIT_SUCCESS;
7969}