blob: 369281a2b61d60694c199e729034c6ccdcda8c27 [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;
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020039 int64_t ret = 0, prev_ret;
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 {
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020068 prev_ret = ret;
69 if (minus) {
70 ret = ret * 10 - (ptr[0] - '0');
71 if (ret > prev_ret) {
72 return 1;
73 }
74 } else {
75 ret = ret * 10 + (ptr[0] - '0');
76 if (ret < prev_ret) {
77 return 1;
78 }
79 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020080 if (str_dig > -1) {
81 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010082 if (ptr[0] == '0') {
83 /* possibly trailing zero */
84 trailing_zeros++;
85 } else {
86 trailing_zeros = 0;
87 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020088 }
89 ++str_exp;
90 }
91 }
Michal Vaskod24dd012016-09-30 12:20:22 +020092 if (str_dig == 0) {
93 /* no digits after '.' */
94 return 1;
95 } else if (str_dig == -1) {
96 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020097 str_dig = 0;
98 }
Radek Krejcibf47a822016-11-04 10:06:08 +010099 /* remove trailing zeros */
100 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +0100101 str_dig -= trailing_zeros;
102 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +0100103 ret = ret / dec_pow(trailing_zeros);
104 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200105
106 /* it's parsed, now adjust the number based on fraction-digits, if needed */
107 if (str_dig < dig) {
108 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200109 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200110 }
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200111 prev_ret = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112 ret *= dec_pow(dig - str_dig);
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200113 if ((minus && (ret > prev_ret)) || (!minus && (ret < prev_ret))) {
114 return 1;
115 }
116
Michal Vasko4d1f0482016-09-19 14:35:06 +0200117 }
118 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200119 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200120 }
121
Michal Vasko4d1f0482016-09-19 14:35:06 +0200122 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200123 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200124
Michal Vaskod24dd012016-09-30 12:20:22 +0200125 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200126}
127
128/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200129 * @brief Parse an identifier.
130 *
131 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
132 * identifier = (ALPHA / "_")
133 * *(ALPHA / DIGIT / "_" / "-" / ".")
134 *
Michal Vaskobb211122015-08-19 14:03:11 +0200135 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200136 *
137 * @return Number of characters successfully parsed.
138 */
Radek Krejcidce5f972017-09-12 15:47:49 +0200139unsigned int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200140parse_identifier(const char *id)
141{
Radek Krejcidce5f972017-09-12 15:47:49 +0200142 unsigned int parsed = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200143
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100144 assert(id);
145
Radek Krejci6dc53a22015-08-17 13:27:59 +0200146 if (!isalpha(id[0]) && (id[0] != '_')) {
147 return -parsed;
148 }
149
150 ++parsed;
151 ++id;
152
153 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
154 ++parsed;
155 ++id;
156 }
157
158 return parsed;
159}
160
161/**
162 * @brief Parse a node-identifier.
163 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200164 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200165 *
Michal Vaskobb211122015-08-19 14:03:11 +0200166 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200167 * @param[out] mod_name Points to the module name, NULL if there is not any.
168 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200169 * @param[out] name Points to the node name.
170 * @param[out] nam_len Length of the node name.
Michal Vasko50576712017-07-28 12:28:33 +0200171 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
172 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200173 *
174 * @return Number of characters successfully parsed,
175 * positive on success, negative on failure.
176 */
177static int
Michal Vasko50576712017-07-28 12:28:33 +0200178parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
179 int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200180{
181 int parsed = 0, ret;
182
183 assert(id);
Michal Vasko50576712017-07-28 12:28:33 +0200184 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
185 assert((name && nam_len) || (!name && !nam_len));
186 assert(!extended || all_desc);
187
Michal Vasko723e50c2015-10-20 15:20:29 +0200188 if (mod_name) {
189 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200190 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200191 }
192 if (name) {
193 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200194 *nam_len = 0;
195 }
196
Michal Vasko50576712017-07-28 12:28:33 +0200197 if (extended) {
198 /* try to parse only the extended expressions */
199 if (id[parsed] == '/') {
200 *all_desc = 1;
201 } else {
202 *all_desc = 0;
203 }
204
205 /* is there a prefix? */
206 ret = parse_identifier(id + *all_desc);
207 if (ret > 0) {
208 if (id[*all_desc + ret] != ':') {
209 /* this is not a prefix, so not an extended id */
210 goto standard_id;
211 }
212
213 if (mod_name) {
214 *mod_name = id + *all_desc;
215 *mod_name_len = ret;
216 }
217
218 /* "/" and ":" */
219 ret += *all_desc + 1;
220 } else {
221 ret = *all_desc;
222 }
223
224 /* parse either "*" or "." */
225 if (!strcmp(id + ret, "*")) {
226 if (name) {
227 *name = id + ret;
228 *nam_len = 1;
229 }
230 ++ret;
231
232 return ret;
233 } else if (!strcmp(id + ret, ".")) {
234 if (!*all_desc) {
235 /* /. is redundant expression, we do not accept it */
236 return -ret;
237 }
238
239 if (name) {
240 *name = id + ret;
241 *nam_len = 1;
242 }
243 ++ret;
244
245 return ret;
246 }
247 /* else a standard id, parse it all again */
248 }
249
250standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200251 if ((ret = parse_identifier(id)) < 1) {
252 return ret;
253 }
254
Michal Vasko723e50c2015-10-20 15:20:29 +0200255 if (mod_name) {
256 *mod_name = id;
Michal Vasko723e50c2015-10-20 15:20:29 +0200257 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200258 }
259
260 parsed += ret;
261 id += ret;
262
263 /* there is prefix */
264 if (id[0] == ':') {
265 ++parsed;
266 ++id;
267
268 /* there isn't */
269 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200270 if (name && mod_name) {
271 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200272 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200273 if (mod_name) {
274 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200275 }
276
Michal Vasko723e50c2015-10-20 15:20:29 +0200277 if (nam_len && mod_name_len) {
278 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200279 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200280 if (mod_name_len) {
281 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200282 }
283
284 return parsed;
285 }
286
287 /* identifier (node name) */
288 if ((ret = parse_identifier(id)) < 1) {
289 return -parsed+ret;
290 }
291
292 if (name) {
293 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200294 *nam_len = ret;
295 }
296
297 return parsed+ret;
298}
299
300/**
301 * @brief Parse a path-predicate (leafref).
302 *
303 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
304 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
305 *
Michal Vaskobb211122015-08-19 14:03:11 +0200306 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200307 * @param[out] prefix Points to the prefix, NULL if there is not any.
308 * @param[out] pref_len Length of the prefix, 0 if there is not any.
309 * @param[out] name Points to the node name.
310 * @param[out] nam_len Length of the node name.
311 * @param[out] path_key_expr Points to the path-key-expr.
312 * @param[out] pke_len Length of the path-key-expr.
313 * @param[out] has_predicate Flag to mark whether there is another predicate following.
314 *
315 * @return Number of characters successfully parsed,
316 * positive on success, negative on failure.
317 */
318static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200319parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
320 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200321{
322 const char *ptr;
323 int parsed = 0, ret;
324
325 assert(id);
326 if (prefix) {
327 *prefix = NULL;
328 }
329 if (pref_len) {
330 *pref_len = 0;
331 }
332 if (name) {
333 *name = NULL;
334 }
335 if (nam_len) {
336 *nam_len = 0;
337 }
338 if (path_key_expr) {
339 *path_key_expr = NULL;
340 }
341 if (pke_len) {
342 *pke_len = 0;
343 }
344 if (has_predicate) {
345 *has_predicate = 0;
346 }
347
348 if (id[0] != '[') {
349 return -parsed;
350 }
351
352 ++parsed;
353 ++id;
354
355 while (isspace(id[0])) {
356 ++parsed;
357 ++id;
358 }
359
Michal Vasko50576712017-07-28 12:28:33 +0200360 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200361 return -parsed+ret;
362 }
363
364 parsed += ret;
365 id += ret;
366
367 while (isspace(id[0])) {
368 ++parsed;
369 ++id;
370 }
371
372 if (id[0] != '=') {
373 return -parsed;
374 }
375
376 ++parsed;
377 ++id;
378
379 while (isspace(id[0])) {
380 ++parsed;
381 ++id;
382 }
383
384 if ((ptr = strchr(id, ']')) == NULL) {
385 return -parsed;
386 }
387
388 --ptr;
389 while (isspace(ptr[0])) {
390 --ptr;
391 }
392 ++ptr;
393
394 ret = ptr-id;
395 if (path_key_expr) {
396 *path_key_expr = id;
397 }
398 if (pke_len) {
399 *pke_len = ret;
400 }
401
402 parsed += ret;
403 id += ret;
404
405 while (isspace(id[0])) {
406 ++parsed;
407 ++id;
408 }
409
410 assert(id[0] == ']');
411
412 if (id[1] == '[') {
413 *has_predicate = 1;
414 }
415
416 return parsed+1;
417}
418
419/**
420 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
421 * the ".." and the first node-identifier, other calls parse a single
422 * node-identifier each.
423 *
424 * path-key-expr = current-function-invocation *WSP "/" *WSP
425 * rel-path-keyexpr
426 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
427 * *(node-identifier *WSP "/" *WSP)
428 * node-identifier
429 *
Michal Vaskobb211122015-08-19 14:03:11 +0200430 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200431 * @param[out] prefix Points to the prefix, NULL if there is not any.
432 * @param[out] pref_len Length of the prefix, 0 if there is not any.
433 * @param[out] name Points to the node name.
434 * @param[out] nam_len Length of the node name.
435 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
436 * must not be changed between consecutive calls.
437 * @return Number of characters successfully parsed,
438 * positive on success, negative on failure.
439 */
440static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200441parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
442 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200443{
444 int parsed = 0, ret, par_times = 0;
445
446 assert(id);
447 assert(parent_times);
448 if (prefix) {
449 *prefix = NULL;
450 }
451 if (pref_len) {
452 *pref_len = 0;
453 }
454 if (name) {
455 *name = NULL;
456 }
457 if (nam_len) {
458 *nam_len = 0;
459 }
460
461 if (!*parent_times) {
462 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
463 if (strncmp(id, "current()", 9)) {
464 return -parsed;
465 }
466
467 parsed += 9;
468 id += 9;
469
470 while (isspace(id[0])) {
471 ++parsed;
472 ++id;
473 }
474
475 if (id[0] != '/') {
476 return -parsed;
477 }
478
479 ++parsed;
480 ++id;
481
482 while (isspace(id[0])) {
483 ++parsed;
484 ++id;
485 }
486
487 /* rel-path-keyexpr */
488 if (strncmp(id, "..", 2)) {
489 return -parsed;
490 }
491 ++par_times;
492
493 parsed += 2;
494 id += 2;
495
496 while (isspace(id[0])) {
497 ++parsed;
498 ++id;
499 }
500 }
501
502 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
503 *
504 * first parent reference with whitespaces already parsed
505 */
506 if (id[0] != '/') {
507 return -parsed;
508 }
509
510 ++parsed;
511 ++id;
512
513 while (isspace(id[0])) {
514 ++parsed;
515 ++id;
516 }
517
518 while (!strncmp(id, "..", 2) && !*parent_times) {
519 ++par_times;
520
521 parsed += 2;
522 id += 2;
523
524 while (isspace(id[0])) {
525 ++parsed;
526 ++id;
527 }
528
529 if (id[0] != '/') {
530 return -parsed;
531 }
532
533 ++parsed;
534 ++id;
535
536 while (isspace(id[0])) {
537 ++parsed;
538 ++id;
539 }
540 }
541
542 if (!*parent_times) {
543 *parent_times = par_times;
544 }
545
546 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200547 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
548 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200549 }
550
551 parsed += ret;
552 id += ret;
553
554 return parsed;
555}
556
557/**
558 * @brief Parse path-arg (leafref).
559 *
560 * path-arg = absolute-path / relative-path
561 * absolute-path = 1*("/" (node-identifier *path-predicate))
562 * relative-path = 1*(".." "/") descendant-path
563 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200564 * @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 +0200565 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200566 * @param[out] prefix Points to the prefix, NULL if there is not any.
567 * @param[out] pref_len Length of the prefix, 0 if there is not any.
568 * @param[out] name Points to the node name.
569 * @param[out] nam_len Length of the node name.
570 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
571 * must not be changed between consecutive calls. -1 if the
572 * path is relative.
573 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
574 *
575 * @return Number of characters successfully parsed,
576 * positive on success, negative on failure.
577 */
578static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200579parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200580 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200581{
582 int parsed = 0, ret, par_times = 0;
583
584 assert(id);
585 assert(parent_times);
586 if (prefix) {
587 *prefix = NULL;
588 }
589 if (pref_len) {
590 *pref_len = 0;
591 }
592 if (name) {
593 *name = NULL;
594 }
595 if (nam_len) {
596 *nam_len = 0;
597 }
598 if (has_predicate) {
599 *has_predicate = 0;
600 }
601
602 if (!*parent_times && !strncmp(id, "..", 2)) {
603 ++par_times;
604
605 parsed += 2;
606 id += 2;
607
608 while (!strncmp(id, "/..", 3)) {
609 ++par_times;
610
611 parsed += 3;
612 id += 3;
613 }
614 }
615
616 if (!*parent_times) {
617 if (par_times) {
618 *parent_times = par_times;
619 } else {
620 *parent_times = -1;
621 }
622 }
623
624 if (id[0] != '/') {
625 return -parsed;
626 }
627
628 /* skip '/' */
629 ++parsed;
630 ++id;
631
632 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200633 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
634 return -parsed - ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200635 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200636 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200637 /* actually we always need prefix even it is not specified */
638 *prefix = lys_main_module(mod)->name;
639 *pref_len = strlen(*prefix);
640 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200641
642 parsed += ret;
643 id += ret;
644
645 /* there is no predicate */
646 if ((id[0] == '/') || !id[0]) {
647 return parsed;
648 } else if (id[0] != '[') {
649 return -parsed;
650 }
651
652 if (has_predicate) {
653 *has_predicate = 1;
654 }
655
656 return parsed;
657}
658
659/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200660 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200661 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200662 *
663 * instance-identifier = 1*("/" (node-identifier *predicate))
664 *
Michal Vaskobb211122015-08-19 14:03:11 +0200665 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200666 * @param[out] model Points to the model name.
667 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200668 * @param[out] name Points to the node name.
669 * @param[out] nam_len Length of the node name.
670 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
671 *
672 * @return Number of characters successfully parsed,
673 * positive on success, negative on failure.
674 */
675static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200676parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
677 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678{
679 int parsed = 0, ret;
680
Michal Vasko1b6ca962017-08-03 14:23:09 +0200681 assert(id && model && mod_len && name && nam_len);
682
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 if (has_predicate) {
684 *has_predicate = 0;
685 }
686
687 if (id[0] != '/') {
688 return -parsed;
689 }
690
691 ++parsed;
692 ++id;
693
Michal Vaskob2f40be2016-09-08 16:03:48 +0200694 if ((ret = parse_identifier(id)) < 1) {
695 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200696 }
697
Michal Vaskob2f40be2016-09-08 16:03:48 +0200698 *name = id;
699 *nam_len = ret;
700
701 parsed += ret;
702 id += ret;
703
Michal Vasko1b6ca962017-08-03 14:23:09 +0200704 if (id[0] == ':') {
705 /* we have prefix */
706 *model = *name;
707 *mod_len = *nam_len;
708
709 ++parsed;
710 ++id;
711
712 if ((ret = parse_identifier(id)) < 1) {
713 return ret;
714 }
715
716 *name = id;
717 *nam_len = ret;
718
719 parsed += ret;
720 id += ret;
721 }
722
Radek Krejci4967cb62016-09-14 16:40:28 +0200723 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200724 *has_predicate = 1;
725 }
726
727 return parsed;
728}
729
730/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200731 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200732 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200733 *
734 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
735 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
736 * ((DQUOTE string DQUOTE) /
737 * (SQUOTE string SQUOTE))
738 * pos = non-negative-integer-value
739 *
Michal Vaskobb211122015-08-19 14:03:11 +0200740 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200741 * @param[out] model Points to the model name.
742 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200743 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
744 * @param[out] nam_len Length of the node name.
745 * @param[out] value Value the node-identifier must have (string from the grammar),
746 * NULL if there is not any.
747 * @param[out] val_len Length of the value, 0 if there is not any.
748 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
749 *
750 * @return Number of characters successfully parsed,
751 * positive on success, negative on failure.
752 */
753static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200754parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
755 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200756{
757 const char *ptr;
758 int parsed = 0, ret;
759 char quote;
760
761 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200762 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200763 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200764 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200765 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200766 }
767 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200768 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200769 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200770 *nam_len = 0;
771 }
772 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200773 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200774 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200775 *val_len = 0;
776 }
777 if (has_predicate) {
778 *has_predicate = 0;
779 }
780
781 if (id[0] != '[') {
782 return -parsed;
783 }
784
785 ++parsed;
786 ++id;
787
788 while (isspace(id[0])) {
789 ++parsed;
790 ++id;
791 }
792
793 /* pos */
794 if (isdigit(id[0])) {
795 if (name) {
796 *name = id;
797 }
798
799 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200800 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200801 }
802
803 while (isdigit(id[0])) {
804 ++parsed;
805 ++id;
806 }
807
808 if (nam_len) {
809 *nam_len = id-(*name);
810 }
811
Michal Vaskof2f28a12016-09-09 12:43:06 +0200812 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200813 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200814 if (id[0] == '.') {
815 if (name) {
816 *name = id;
817 }
818 if (nam_len) {
819 *nam_len = 1;
820 }
821
822 ++parsed;
823 ++id;
824
825 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200826 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200827 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200828 }
829
830 parsed += ret;
831 id += ret;
832 }
833
834 while (isspace(id[0])) {
835 ++parsed;
836 ++id;
837 }
838
839 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200840 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200841 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200842
Radek Krejci6dc53a22015-08-17 13:27:59 +0200843 ++parsed;
844 ++id;
845
Michal Vaskof2f28a12016-09-09 12:43:06 +0200846 while (isspace(id[0])) {
847 ++parsed;
848 ++id;
849 }
850
851 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
852 if ((id[0] == '\"') || (id[0] == '\'')) {
853 quote = id[0];
854
855 ++parsed;
856 ++id;
857
858 if ((ptr = strchr(id, quote)) == NULL) {
859 return -parsed;
860 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200861 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200862
863 if (value) {
864 *value = id;
865 }
866 if (val_len) {
867 *val_len = ret;
868 }
869
Michal Vasko1b6ca962017-08-03 14:23:09 +0200870 parsed += ret + 1;
871 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200872 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200873 return -parsed;
874 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200875 }
876
877 while (isspace(id[0])) {
878 ++parsed;
879 ++id;
880 }
881
882 if (id[0] != ']') {
883 return -parsed;
884 }
885
886 ++parsed;
887 ++id;
888
889 if ((id[0] == '[') && has_predicate) {
890 *has_predicate = 1;
891 }
892
893 return parsed;
894}
895
896/**
897 * @brief Parse schema-nodeid.
898 *
899 * schema-nodeid = absolute-schema-nodeid /
900 * descendant-schema-nodeid
901 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200902 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200903 * node-identifier
904 * absolute-schema-nodeid
905 *
Michal Vaskobb211122015-08-19 14:03:11 +0200906 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200907 * @param[out] mod_name Points to the module name, NULL if there is not any.
908 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200909 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200910 * @param[out] nam_len Length of the node name.
911 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
912 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100913 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
914 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200915 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200916 *
917 * @return Number of characters successfully parsed,
918 * positive on success, negative on failure.
919 */
Michal Vasko22448d32016-03-16 13:17:29 +0100920int
Michal Vasko723e50c2015-10-20 15:20:29 +0200921parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko50576712017-07-28 12:28:33 +0200922 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200923{
924 int parsed = 0, ret;
925
926 assert(id);
927 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200928
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100929 if (has_predicate) {
930 *has_predicate = 0;
931 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200932
933 if (id[0] != '/') {
934 if (*is_relative != -1) {
935 return -parsed;
936 } else {
937 *is_relative = 1;
938 }
Michal Vasko48935352016-03-29 11:52:36 +0200939 if (!strncmp(id, "./", 2)) {
940 parsed += 2;
941 id += 2;
942 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200943 } else {
944 if (*is_relative == -1) {
945 *is_relative = 0;
946 }
947 ++parsed;
948 ++id;
949 }
950
Michal Vasko50576712017-07-28 12:28:33 +0200951 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
952 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200953 }
954
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100955 parsed += ret;
956 id += ret;
957
958 if ((id[0] == '[') && has_predicate) {
959 *has_predicate = 1;
960 }
961
962 return parsed;
963}
964
965/**
966 * @brief Parse schema predicate (special format internally used).
967 *
968 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200969 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100970 * key-with-value = identifier *WSP "=" *WSP
971 * ((DQUOTE string DQUOTE) /
972 * (SQUOTE string SQUOTE))
973 *
974 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200975 * @param[out] mod_name Points to the list key module name.
976 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100977 * @param[out] name Points to the list key name.
978 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100979 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100980 * @param[out] val_len Length of \p value.
981 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
982 */
Michal Vasko22448d32016-03-16 13:17:29 +0100983int
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200984parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
985 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100986{
987 const char *ptr;
988 int parsed = 0, ret;
989 char quote;
990
991 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200992 if (mod_name) {
993 *mod_name = NULL;
994 }
995 if (mod_name_len) {
996 *mod_name_len = 0;
997 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100998 if (name) {
999 *name = NULL;
1000 }
1001 if (nam_len) {
1002 *nam_len = 0;
1003 }
1004 if (value) {
1005 *value = NULL;
1006 }
1007 if (val_len) {
1008 *val_len = 0;
1009 }
1010 if (has_predicate) {
1011 *has_predicate = 0;
1012 }
1013
1014 if (id[0] != '[') {
1015 return -parsed;
1016 }
1017
1018 ++parsed;
1019 ++id;
1020
1021 while (isspace(id[0])) {
1022 ++parsed;
1023 ++id;
1024 }
1025
Michal Vasko22448d32016-03-16 13:17:29 +01001026 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001027 if (id[0] == '.') {
1028 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001029
1030 if (name) {
1031 *name = id;
1032 }
1033 if (nam_len) {
1034 *nam_len = ret;
1035 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001036 } else if (isdigit(id[0])) {
1037 if (id[0] == '0') {
1038 return -parsed;
1039 }
1040 ret = 1;
1041 while (isdigit(id[ret])) {
1042 ++ret;
1043 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001044
1045 if (name) {
1046 *name = id;
1047 }
1048 if (nam_len) {
1049 *nam_len = ret;
1050 }
Michal Vasko50576712017-07-28 12:28:33 +02001051 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001052 return -parsed + ret;
1053 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001054
1055 parsed += ret;
1056 id += ret;
1057
1058 while (isspace(id[0])) {
1059 ++parsed;
1060 ++id;
1061 }
1062
1063 /* there is value as well */
1064 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001065 if (name && isdigit(**name)) {
1066 return -parsed;
1067 }
1068
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001069 ++parsed;
1070 ++id;
1071
1072 while (isspace(id[0])) {
1073 ++parsed;
1074 ++id;
1075 }
1076
1077 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1078 if ((id[0] == '\"') || (id[0] == '\'')) {
1079 quote = id[0];
1080
1081 ++parsed;
1082 ++id;
1083
1084 if ((ptr = strchr(id, quote)) == NULL) {
1085 return -parsed;
1086 }
1087 ret = ptr - id;
1088
1089 if (value) {
1090 *value = id;
1091 }
1092 if (val_len) {
1093 *val_len = ret;
1094 }
1095
1096 parsed += ret + 1;
1097 id += ret + 1;
1098 } else {
1099 return -parsed;
1100 }
1101
1102 while (isspace(id[0])) {
1103 ++parsed;
1104 ++id;
1105 }
1106 }
1107
1108 if (id[0] != ']') {
1109 return -parsed;
1110 }
1111
1112 ++parsed;
1113 ++id;
1114
1115 if ((id[0] == '[') && has_predicate) {
1116 *has_predicate = 1;
1117 }
1118
1119 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001120}
1121
1122/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001123 * @brief Resolve (find) a feature definition. Logs directly.
1124 *
1125 * @param[in] feat_name Feature name to resolve.
1126 * @param[in] len Length of \p feat_name.
1127 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001128 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1129 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001130 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001131 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001132 */
1133static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135{
1136 char *str;
1137 const char *mod_name, *name;
1138 int mod_name_len, nam_len, i, j;
1139 const struct lys_module *module;
1140
Radek Krejci9ff0a922016-07-14 13:08:05 +02001141 assert(feature);
1142
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001143 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001144 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0)) < 1) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001145 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1146 return -1;
1147 }
1148
1149 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1150 if (!module) {
1151 /* identity refers unknown data model */
1152 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1153 return -1;
1154 }
1155
Radek Krejci9ff0a922016-07-14 13:08:05 +02001156 if (module != node->module && module == lys_node_module(node)) {
1157 /* first, try to search directly in submodule where the feature was mentioned */
1158 for (j = 0; j < node->module->features_size; j++) {
1159 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1160 /* check status */
1161 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001162 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001163 return -1;
1164 }
1165 *feature = &node->module->features[j];
1166 return 0;
1167 }
1168 }
1169 }
1170
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001171 /* search in the identified module ... */
1172 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001173 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001174 /* check status */
1175 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001176 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001177 return -1;
1178 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001179 *feature = &module->features[j];
1180 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001181 }
1182 }
1183 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001184 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001185 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001186 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1187 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001188 /* check status */
1189 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1190 module->inc[i].submodule->features[j].flags,
1191 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001192 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001193 return -1;
1194 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001195 *feature = &module->inc[i].submodule->features[j];
1196 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001197 }
1198 }
1199 }
1200
1201 /* not found */
1202 str = strndup(feat_name, len);
1203 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1204 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001205 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001206}
1207
Radek Krejci9ff0a922016-07-14 13:08:05 +02001208/*
1209 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001210 * - 1 if enabled
1211 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001212 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001213static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001214resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001215{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001216 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001217
Radek Krejci9ff0a922016-07-14 13:08:05 +02001218 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001219 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001220 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001221 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001222 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001223
Radek Krejci69b8d922016-07-27 13:13:41 +02001224 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001225}
1226
1227static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001228resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001229{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001230 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001231 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001232
Radek Krejci9ff0a922016-07-14 13:08:05 +02001233 op = iff_getop(expr->expr, *index_e);
1234 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001235
Radek Krejci9ff0a922016-07-14 13:08:05 +02001236 switch (op) {
1237 case LYS_IFF_F:
1238 /* resolve feature */
1239 return resolve_feature_value(expr->features[(*index_f)++]);
1240 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001241 /* invert result */
1242 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001243 case LYS_IFF_AND:
1244 case LYS_IFF_OR:
1245 a = resolve_iffeature_recursive(expr, index_e, index_f);
1246 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001247 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001248 return a && b;
1249 } else { /* LYS_IFF_OR */
1250 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001251 }
1252 }
1253
Radek Krejciaf566332017-02-07 15:56:59 +01001254 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001255}
1256
1257int
1258resolve_iffeature(struct lys_iffeature *expr)
1259{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001260 int index_e = 0, index_f = 0;
1261
1262 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001263 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001264 }
Radek Krejciaf566332017-02-07 15:56:59 +01001265 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001266}
1267
1268struct iff_stack {
1269 int size;
1270 int index; /* first empty item */
1271 uint8_t *stack;
1272};
1273
1274static int
1275iff_stack_push(struct iff_stack *stack, uint8_t value)
1276{
1277 if (stack->index == stack->size) {
1278 stack->size += 4;
1279 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001280 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM; stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001281 }
1282
1283 stack->stack[stack->index++] = value;
1284 return EXIT_SUCCESS;
1285}
1286
1287static uint8_t
1288iff_stack_pop(struct iff_stack *stack)
1289{
1290 stack->index--;
1291 return stack->stack[stack->index];
1292}
1293
1294static void
1295iff_stack_clean(struct iff_stack *stack)
1296{
1297 stack->size = 0;
1298 free(stack->stack);
1299}
1300
1301static void
1302iff_setop(uint8_t *list, uint8_t op, int pos)
1303{
1304 uint8_t *item;
1305 uint8_t mask = 3;
1306
1307 assert(pos >= 0);
1308 assert(op <= 3); /* max 2 bits */
1309
1310 item = &list[pos / 4];
1311 mask = mask << 2 * (pos % 4);
1312 *item = (*item) & ~mask;
1313 *item = (*item) | (op << 2 * (pos % 4));
1314}
1315
1316uint8_t
1317iff_getop(uint8_t *list, int pos)
1318{
1319 uint8_t *item;
1320 uint8_t mask = 3, result;
1321
1322 assert(pos >= 0);
1323
1324 item = &list[pos / 4];
1325 result = (*item) & (mask << 2 * (pos % 4));
1326 return result >> 2 * (pos % 4);
1327}
1328
1329#define LYS_IFF_LP 0x04 /* ( */
1330#define LYS_IFF_RP 0x08 /* ) */
1331
Radek Krejcicbb473e2016-09-16 14:48:32 +02001332/* internal structure for passing data for UNRES_IFFEAT */
1333struct unres_iffeat_data {
1334 struct lys_node *node;
1335 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001336 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001337};
1338
Radek Krejci9ff0a922016-07-14 13:08:05 +02001339void
1340resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1341{
1342 unsigned int e = 0, f = 0, r = 0;
1343 uint8_t op;
1344
1345 assert(iffeat);
1346
1347 if (!iffeat->expr) {
1348 goto result;
1349 }
1350
1351 do {
1352 op = iff_getop(iffeat->expr, e++);
1353 switch (op) {
1354 case LYS_IFF_NOT:
1355 if (!r) {
1356 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001357 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001358 break;
1359 case LYS_IFF_AND:
1360 case LYS_IFF_OR:
1361 if (!r) {
1362 r += 2;
1363 } else {
1364 r += 1;
1365 }
1366 break;
1367 case LYS_IFF_F:
1368 f++;
1369 if (r) {
1370 r--;
1371 }
1372 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001373 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001374 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001375
Radek Krejci9ff0a922016-07-14 13:08:05 +02001376result:
1377 if (expr_size) {
1378 *expr_size = e;
1379 }
1380 if (feat_size) {
1381 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001382 }
1383}
1384
1385int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001386resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001387 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001388{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001389 const char *c = value;
1390 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001391 int i, j, last_not, checkversion = 0;
1392 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001393 uint8_t op;
1394 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001395 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001396
Radek Krejci9ff0a922016-07-14 13:08:05 +02001397 assert(c);
1398
1399 if (isspace(c[0])) {
1400 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1401 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001402 }
1403
Radek Krejci9ff0a922016-07-14 13:08:05 +02001404 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1405 for (i = j = last_not = 0; c[i]; i++) {
1406 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001407 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001408 j++;
1409 continue;
1410 } else if (c[i] == ')') {
1411 j--;
1412 continue;
1413 } else if (isspace(c[i])) {
1414 continue;
1415 }
1416
1417 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1418 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001419 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001420 return EXIT_FAILURE;
1421 } else if (!isspace(c[i + r])) {
1422 /* feature name starting with the not/and/or */
1423 last_not = 0;
1424 f_size++;
1425 } else if (c[i] == 'n') { /* not operation */
1426 if (last_not) {
1427 /* double not */
1428 expr_size = expr_size - 2;
1429 last_not = 0;
1430 } else {
1431 last_not = 1;
1432 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001433 } else { /* and, or */
1434 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001435 /* not a not operation */
1436 last_not = 0;
1437 }
1438 i += r;
1439 } else {
1440 f_size++;
1441 last_not = 0;
1442 }
1443 expr_size++;
1444
1445 while (!isspace(c[i])) {
1446 if (!c[i] || c[i] == ')') {
1447 i--;
1448 break;
1449 }
1450 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001451 }
1452 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001453 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001454 /* not matching count of ( and ) */
1455 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1456 return EXIT_FAILURE;
1457 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001458
Radek Krejci69b8d922016-07-27 13:13:41 +02001459 if (checkversion || expr_size > 1) {
1460 /* check that we have 1.1 module */
1461 if (node->module->version != 2) {
1462 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1463 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1464 return EXIT_FAILURE;
1465 }
1466 }
1467
Radek Krejci9ff0a922016-07-14 13:08:05 +02001468 /* allocate the memory */
1469 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001470 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001471 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001472 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM, error);
1473 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001474 f_size--; expr_size--; /* used as indexes from now */
1475
1476 for (i--; i >= 0; i--) {
1477 if (c[i] == ')') {
1478 /* push it on stack */
1479 iff_stack_push(&stack, LYS_IFF_RP);
1480 continue;
1481 } else if (c[i] == '(') {
1482 /* pop from the stack into result all operators until ) */
1483 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1484 iff_setop(iffeat_expr->expr, op, expr_size--);
1485 }
1486 continue;
1487 } else if (isspace(c[i])) {
1488 continue;
1489 }
1490
1491 /* end operator or operand -> find beginning and get what is it */
1492 j = i + 1;
1493 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1494 i--;
1495 }
1496 i++; /* get back by one step */
1497
1498 if (!strncmp(&c[i], "not ", 4)) {
1499 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1500 /* double not */
1501 iff_stack_pop(&stack);
1502 } else {
1503 /* not has the highest priority, so do not pop from the stack
1504 * as in case of AND and OR */
1505 iff_stack_push(&stack, LYS_IFF_NOT);
1506 }
1507 } else if (!strncmp(&c[i], "and ", 4)) {
1508 /* as for OR - pop from the stack all operators with the same or higher
1509 * priority and store them to the result, then push the AND to the stack */
1510 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1511 op = iff_stack_pop(&stack);
1512 iff_setop(iffeat_expr->expr, op, expr_size--);
1513 }
1514 iff_stack_push(&stack, LYS_IFF_AND);
1515 } else if (!strncmp(&c[i], "or ", 3)) {
1516 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1517 op = iff_stack_pop(&stack);
1518 iff_setop(iffeat_expr->expr, op, expr_size--);
1519 }
1520 iff_stack_push(&stack, LYS_IFF_OR);
1521 } else {
1522 /* feature name, length is j - i */
1523
1524 /* add it to the result */
1525 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1526
1527 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001528 * forward referenced, we have to keep the feature name in auxiliary
1529 * structure passed into unres */
1530 iff_data = malloc(sizeof *iff_data);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001531 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM, error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001532 iff_data->node = node;
1533 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001534 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001535 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1536 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001537 f_size--;
1538
1539 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001540 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001541 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001542 }
1543 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001544 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001545 while (stack.index) {
1546 op = iff_stack_pop(&stack);
1547 iff_setop(iffeat_expr->expr, op, expr_size--);
1548 }
1549
1550 if (++expr_size || ++f_size) {
1551 /* not all expected operators and operands found */
1552 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1553 rc = EXIT_FAILURE;
1554 } else {
1555 rc = EXIT_SUCCESS;
1556 }
1557
1558error:
1559 /* cleanup */
1560 iff_stack_clean(&stack);
1561
1562 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001563}
1564
1565/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001566 * @brief Resolve (find) a data node based on a schema-nodeid.
1567 *
1568 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1569 * module).
1570 *
1571 */
1572struct lyd_node *
1573resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1574{
1575 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001576 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001577 const struct lys_node *schema = NULL;
1578
1579 assert(nodeid && start);
1580
1581 if (nodeid[0] == '/') {
1582 return NULL;
1583 }
1584
1585 str = p = strdup(nodeid);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001586 LY_CHECK_ERR_RETURN(!str, LOGMEM, NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001587
Michal Vasko3edeaf72016-02-11 13:17:43 +01001588 while (p) {
1589 token = p;
1590 p = strchr(p, '/');
1591 if (p) {
1592 *p = '\0';
1593 p++;
1594 }
1595
Radek Krejci5da4eb62016-04-08 14:45:51 +02001596 if (p) {
1597 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001598 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001599 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001600 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001601 result = NULL;
1602 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001603 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001604
Radek Krejci5da4eb62016-04-08 14:45:51 +02001605 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1606 continue;
1607 }
1608 } else {
1609 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001610 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001611 || !schema) {
1612 result = NULL;
1613 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001614 }
1615 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001616 LY_TREE_FOR(result ? result->child : start, iter) {
1617 if (iter->schema == schema) {
1618 /* move in data tree according to returned schema */
1619 result = iter;
1620 break;
1621 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001622 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001623 if (!iter) {
1624 /* instance not found */
1625 result = NULL;
1626 break;
1627 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001628 }
1629 free(str);
1630
1631 return result;
1632}
1633
Radek Krejci1a9c3612017-04-24 14:49:43 +02001634int
Michal Vasko50576712017-07-28 12:28:33 +02001635schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1636 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001637{
1638 const struct lys_module *prefix_mod;
1639
Michal Vasko50576712017-07-28 12:28:33 +02001640 /* name check */
1641 if ((name[0] != '*') && (name[0] != '.') && (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len])) {
1642 return 1;
1643 }
1644
Radek Krejcibdf92362016-04-08 14:43:34 +02001645 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001646 if (mod_name) {
1647 prefix_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
1648 if (!prefix_mod) {
1649 return -1;
1650 }
1651 } else {
1652 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001653 }
1654 if (prefix_mod != lys_node_module(sibling)) {
1655 return 1;
1656 }
1657
Michal Vasko50576712017-07-28 12:28:33 +02001658 /* match */
1659 switch (name[0]) {
1660 case '*':
1661 return 2;
1662 case '.':
1663 return 3;
1664 default:
Radek Krejcibdf92362016-04-08 14:43:34 +02001665 return 0;
1666 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001667}
1668
Michal Vasko50576712017-07-28 12:28:33 +02001669/* keys do not have to be ordered and do not have to be all of them */
1670static int
1671resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1672 const struct lys_module *cur_module, int *nodeid_end)
1673{
1674 int mod_len, nam_len, has_predicate, r, i;
1675 const char *model, *name;
1676 struct lys_node_list *list;
1677
1678 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1679 return 1;
1680 }
1681
1682 list = (struct lys_node_list *)node;
1683 do {
1684 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1685 if (r < 1) {
1686 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
1687 return -1;
1688 }
1689 nodeid += r;
1690
1691 if (node->nodetype == LYS_LEAFLIST) {
1692 /* just check syntax */
1693 if (model || !name || (name[0] != '.') || has_predicate) {
1694 return 1;
1695 }
1696 break;
1697 } else {
1698 /* check the key */
1699 for (i = 0; i < list->keys_size; ++i) {
1700 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1701 continue;
1702 }
1703 if (model) {
1704 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1705 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1706 continue;
1707 }
1708 } else {
1709 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1710 continue;
1711 }
1712 }
1713
1714 /* match */
1715 break;
1716 }
1717
1718 if (i == list->keys_size) {
1719 return 1;
1720 }
1721 }
1722 } while (has_predicate);
1723
1724 if (!nodeid[0]) {
1725 *nodeid_end = 1;
1726 }
1727 return 0;
1728}
1729
1730/* start - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001731 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001732int
Michal Vasko50576712017-07-28 12:28:33 +02001733resolve_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
1734 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001735{
Michal Vaskobb520442017-05-23 10:55:18 +02001736 const char *name, *mod_name, *id;
Michal Vasko50576712017-07-28 12:28:33 +02001737 const struct lys_node *sibling, *start_parent, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001738 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001739 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001740 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001741 const struct lys_module *start_mod, *aux_mod;
Michal Vasko50576712017-07-28 12:28:33 +02001742 char *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001743
Michal Vasko50576712017-07-28 12:28:33 +02001744 assert(nodeid && (start || cur_module) && ret);
1745 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001746
Michal Vasko50576712017-07-28 12:28:33 +02001747 if (!cur_module) {
1748 cur_module = lys_node_module(start);
1749 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001750 id = nodeid;
1751
Michal Vasko50576712017-07-28 12:28:33 +02001752 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1753 (extended ? &all_desc : NULL), extended);
1754 if (r < 1) {
1755 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1756 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001757 }
1758 id += r;
1759
Michal Vasko50576712017-07-28 12:28:33 +02001760 if (is_relative && !start) {
1761 LOGINT;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001762 return -1;
1763 }
1764
1765 /* descendant-schema-nodeid */
1766 if (is_relative) {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001767 cur_module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001768 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001769
Michal Vasko3edeaf72016-02-11 13:17:43 +01001770 /* absolute-schema-nodeid */
1771 } else {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001772 start_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001773 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001774 str = strndup(mod_name, mod_name_len);
1775 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1776 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001777 return -1;
1778 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001779 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001780 }
1781
1782 while (1) {
1783 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001784 last_aug = NULL;
1785
1786 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001787 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1788 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001789 /* we are getting into another module (augment) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001790 aux_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskobb520442017-05-23 10:55:18 +02001791 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001792 str = strndup(mod_name, mod_name_len);
1793 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1794 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001795 return -1;
1796 }
1797 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001798 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001799 * because this module may be not implemented and it augments something in another module and
1800 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001801 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001802 }
1803
1804 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001805 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001806get_next_augment:
1807 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1808 }
1809 }
1810
1811 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001812 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001813 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1814
1815 /* resolve predicate */
1816 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1817 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1818 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001819 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001820 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001821 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001822 }
Michal Vasko50576712017-07-28 12:28:33 +02001823 } else if (!id[0]) {
1824 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001825 }
Michal Vasko50576712017-07-28 12:28:33 +02001826
1827 if (r == 0) {
1828 /* one matching result */
1829 if (nodeid_end) {
1830 *ret = ly_set_new();
1831 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1832 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1833 } else {
1834 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1835 return -1;
1836 }
1837 start_parent = sibling;
1838 }
1839 break;
1840 } else if (r == 1) {
1841 continue;
1842 } else if (r == 2) {
1843 /* "*" */
1844 if (!*ret) {
1845 *ret = ly_set_new();
1846 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1847 }
1848 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1849 if (all_desc) {
1850 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1851 if (elem != sibling) {
1852 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1853 }
1854
1855 LY_TREE_DFS_END(sibling, next, elem);
1856 }
1857 }
1858 } else if (r == 3) {
1859 /* "." */
1860 if (!*ret) {
1861 *ret = ly_set_new();
1862 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1863 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1864 }
1865 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1866 if (all_desc) {
1867 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1868 if (elem != sibling) {
1869 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1870 }
1871
1872 LY_TREE_DFS_END(sibling, next, elem);
1873 }
1874 }
1875 } else {
1876 LOGINT;
1877 return -1;
1878 }
1879 }
1880
1881 /* skip predicate */
1882 if (extended && has_predicate) {
1883 while (id[0] == '[') {
1884 id = strchr(id, ']');
1885 if (!id) {
1886 LOGINT;
1887 return -1;
1888 }
1889 ++id;
1890 }
1891 }
1892
1893 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1894 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001895 }
1896
1897 /* no match */
1898 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001899 if (last_aug) {
1900 /* it still could be in another augment */
1901 goto get_next_augment;
1902 }
Michal Vasko50576712017-07-28 12:28:33 +02001903 if (no_node_error) {
1904 str = strndup(nodeid, (name - nodeid) + nam_len);
1905 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1906 free(str);
1907 return -1;
1908 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001909 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001910 return EXIT_SUCCESS;
1911 }
1912
Michal Vasko50576712017-07-28 12:28:33 +02001913 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1914 (extended ? &all_desc : NULL), extended);
1915 if (r < 1) {
1916 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1917 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001918 }
1919 id += r;
1920 }
1921
1922 /* cannot get here */
1923 LOGINT;
1924 return -1;
1925}
1926
Radek Krejcif3c71de2016-04-11 12:45:46 +02001927/* unique, refine,
1928 * >0 - unexpected char on position (ret - 1),
1929 * 0 - ok (but ret can still be NULL),
1930 * -1 - error,
1931 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001932int
1933resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001934 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001935{
1936 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001937 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 int r, nam_len, mod_name_len, is_relative = -1;
1939 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001940 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001942 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001943 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001944
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001945 if (!start) {
1946 /* leaf not found */
1947 return 0;
1948 }
1949
Michal Vasko3edeaf72016-02-11 13:17:43 +01001950 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02001951 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001952
Michal Vasko50576712017-07-28 12:28:33 +02001953 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001954 return ((id - nodeid) - r) + 1;
1955 }
1956 id += r;
1957
1958 if (!is_relative) {
1959 return -1;
1960 }
1961
Michal Vasko24476fa2017-03-08 12:33:48 +01001962 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001963 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001964 start_parent = lys_parent(start_parent);
1965 }
1966
Michal Vasko3edeaf72016-02-11 13:17:43 +01001967 while (1) {
1968 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001969 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001970 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001971 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
1972 if (r == 0) {
1973 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001974 if (!(sibling->nodetype & ret_nodetype)) {
1975 /* wrong node type, too bad */
1976 continue;
1977 }
1978 *ret = sibling;
1979 return EXIT_SUCCESS;
1980 }
Michal Vasko50576712017-07-28 12:28:33 +02001981 start_parent = sibling;
1982 break;
1983 } else if (r == 1) {
1984 continue;
1985 } else {
1986 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001987 }
1988 }
1989
1990 /* no match */
1991 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001992 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001993 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001994 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1995 *ret = NULL;
1996 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001997 }
1998
Michal Vasko50576712017-07-28 12:28:33 +02001999 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002000 return ((id - nodeid) - r) + 1;
2001 }
2002 id += r;
2003 }
2004
2005 /* cannot get here */
2006 LOGINT;
2007 return -1;
2008}
2009
2010/* choice default */
2011int
2012resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2013{
2014 /* cannot actually be a path */
2015 if (strchr(nodeid, '/')) {
2016 return -1;
2017 }
2018
Michal Vaskodc300b02017-04-07 14:09:20 +02002019 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002020}
2021
2022/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2023static int
2024resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2025{
2026 const struct lys_module *module;
2027 const char *mod_prefix, *name;
2028 int i, mod_prefix_len, nam_len;
2029
2030 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002031 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len, NULL, 0)) < 1) || nodeid[i]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002032 return -i + 1;
2033 }
2034
2035 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
2036 if (!module) {
2037 return -1;
2038 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002039 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002040 start = module->data;
2041 }
2042
2043 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2044
2045 return EXIT_SUCCESS;
2046}
2047
2048int
2049resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2050 const struct lys_node **ret)
2051{
2052 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002053 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002054 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002055 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002056
2057 assert(nodeid && module && ret);
2058 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2059
2060 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002061 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002062
Michal Vasko50576712017-07-28 12:28:33 +02002063 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002064 return ((id - nodeid) - r) + 1;
2065 }
2066 id += r;
2067
2068 if (is_relative) {
2069 return -1;
2070 }
2071
2072 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01002073 if (!abs_start_mod) {
2074 return -1;
2075 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002076
2077 while (1) {
2078 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002079 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01002080 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
Michal Vasko50576712017-07-28 12:28:33 +02002081 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2082 if (r == 0) {
2083 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002084 if (!(sibling->nodetype & ret_nodetype)) {
2085 /* wrong node type, too bad */
2086 continue;
2087 }
2088 *ret = sibling;
2089 return EXIT_SUCCESS;
2090 }
Michal Vasko50576712017-07-28 12:28:33 +02002091 start_parent = sibling;
2092 break;
2093 } else if (r == 1) {
2094 continue;
2095 } else {
2096 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002097 }
2098 }
2099
2100 /* no match */
2101 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002102 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002103 return EXIT_SUCCESS;
2104 }
2105
Michal Vasko50576712017-07-28 12:28:33 +02002106 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002107 return ((id - nodeid) - r) + 1;
2108 }
2109 id += r;
2110 }
2111
2112 /* cannot get here */
2113 LOGINT;
2114 return -1;
2115}
2116
Michal Vaskoe733d682016-03-14 09:08:27 +01002117static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002118resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002119{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002120 const char *mod_name, *name;
2121 int mod_name_len, nam_len, has_predicate, i;
2122 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002123
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002124 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 +02002125 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002126 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002127 return -1;
2128 }
2129
2130 predicate += i;
2131 *parsed += i;
2132
Michal Vasko58c2aab2017-01-05 10:02:05 +01002133 if (!isdigit(name[0])) {
2134 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002135 key = (struct lys_node *)list->keys[i];
2136 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002137 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002138 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002139 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002140
Michal Vasko58c2aab2017-01-05 10:02:05 +01002141 if (i == list->keys_size) {
2142 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2143 return -1;
2144 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002145 }
2146
2147 /* more predicates? */
2148 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002149 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002150 }
2151
2152 return 0;
2153}
2154
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002155/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002156const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002157resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002158{
Michal Vasko10728b52016-04-07 14:26:29 +02002159 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002160 const char *name, *mod_name, *id;
Michal Vaskob3744402017-08-03 14:23:58 +02002161 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002162 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002163 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002164 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002165
Michal Vasko3547c532016-03-14 09:40:50 +01002166 assert(nodeid && (ctx || start));
2167 if (!ctx) {
2168 ctx = start->module->ctx;
2169 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002170
2171 id = nodeid;
2172
Michal Vasko50576712017-07-28 12:28:33 +02002173 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002174 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002175 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002176 }
2177 id += r;
2178
2179 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002180 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002181 start_parent = start;
2182 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2183 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002184 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002185 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002186 } else {
2187 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002188 str = strndup(nodeid, (name + nam_len) - nodeid);
2189 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2190 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002191 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002192 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2193 LOGINT;
2194 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002195 }
2196
Michal Vasko971a3ca2016-04-01 13:09:29 +02002197 if (ly_buf_used && module_name[0]) {
2198 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2199 }
2200 ly_buf_used++;
2201
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002202 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002203 module_name[mod_name_len] = '\0';
Michal Vaskof68a49e2017-08-14 13:23:37 +02002204 module = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002205
2206 if (buf_backup) {
2207 /* return previous internal buffer content */
2208 strcpy(module_name, buf_backup);
2209 free(buf_backup);
2210 buf_backup = NULL;
2211 }
2212 ly_buf_used--;
2213
Michal Vaskof68a49e2017-08-14 13:23:37 +02002214 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002215 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2216 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2217 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002218 return NULL;
2219 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002220 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002221
2222 /* now it's as if there was no module name */
2223 mod_name = NULL;
2224 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002225 }
2226
Michal Vaskof68a49e2017-08-14 13:23:37 +02002227 prev_mod = module;
2228
Michal Vasko3edeaf72016-02-11 13:17:43 +01002229 while (1) {
2230 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002231 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002232 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002233 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002234 /* output check */
2235 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2236 if (parent) {
2237 if (output && (parent->nodetype == LYS_INPUT)) {
2238 continue;
2239 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2240 continue;
2241 }
2242 }
2243
Michal Vasko3edeaf72016-02-11 13:17:43 +01002244 /* module check */
2245 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002246 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002247 LOGINT;
2248 return NULL;
2249 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002250
2251 if (ly_buf_used && module_name[0]) {
2252 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2253 }
2254 ly_buf_used++;
2255
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002256 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002257 module_name[mod_name_len] = '\0';
2258 /* will also find an augment module */
2259 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002260
2261 if (buf_backup) {
2262 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002263 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002264 free(buf_backup);
2265 buf_backup = NULL;
2266 }
2267 ly_buf_used--;
2268
Michal Vasko3edeaf72016-02-11 13:17:43 +01002269 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002270 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2271 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2272 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002273 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002274 }
2275 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002276 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002277 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002278 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002279 continue;
2280 }
2281
Michal Vaskoe733d682016-03-14 09:08:27 +01002282 /* do we have some predicates on it? */
2283 if (has_predicate) {
2284 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002285 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002286 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002287 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2288 return NULL;
2289 }
2290 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002291 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002292 return NULL;
2293 }
2294 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002295 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002296 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002297 }
2298 id += r;
2299 }
2300
Michal Vasko3edeaf72016-02-11 13:17:43 +01002301 /* the result node? */
2302 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002303 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002304 }
2305
Michal Vaskodc300b02017-04-07 14:09:20 +02002306 /* move down the tree, if possible */
2307 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2308 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2309 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002310 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002311 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002312
2313 /* update prev mod */
2314 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002315 break;
2316 }
2317 }
2318
2319 /* no match */
2320 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002321 str = strndup(nodeid, (name + nam_len) - nodeid);
2322 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2323 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002324 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002325 }
2326
Michal Vasko50576712017-07-28 12:28:33 +02002327 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002328 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002329 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002330 }
2331 id += r;
2332 }
2333
2334 /* cannot get here */
2335 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002336 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002337}
2338
Michal Vasko22448d32016-03-16 13:17:29 +01002339static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002340resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko50576712017-07-28 12:28:33 +02002341 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002342{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002343 const char *mod_name, *name, *value, *key_val;
2344 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002345 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002346 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002347
Radek Krejci61a86c62016-03-24 11:06:44 +01002348 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002349 assert(node->schema->nodetype == LYS_LIST);
2350
Michal Vasko53adfc72017-01-06 10:39:10 +01002351 /* is the predicate a number? */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002352 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 +01002353 || !strncmp(name, ".", nam_len)) {
2354 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2355 return -1;
2356 }
2357
2358 if (isdigit(name[0])) {
2359 if (position == atoi(name)) {
2360 /* match */
2361 *parsed += r;
2362 return 0;
2363 } else {
2364 /* not a match */
2365 return 1;
2366 }
2367 }
2368
2369 if (!((struct lys_node_list *)node->schema)->keys_size) {
2370 /* no keys in schema - causes an error later */
2371 return 0;
2372 }
2373
Michal Vaskof29903d2016-04-18 13:13:10 +02002374 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002375 if (!key) {
2376 /* it is not a position, so we need a key for it to be a match */
2377 return 1;
2378 }
2379
2380 /* go through all the keys */
2381 i = 0;
2382 goto check_parsed_values;
2383
2384 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002385 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002386 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002387 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002388 }
2389
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002390 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 +02002391 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002392 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002393 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002394 }
2395
Michal Vasko53adfc72017-01-06 10:39:10 +01002396check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002397 predicate += r;
2398 *parsed += r;
2399
Michal Vaskof29903d2016-04-18 13:13:10 +02002400 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002401 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002402 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002403 }
2404
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002405 if (mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002406 /* specific module, check that the found key is from that module */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002407 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2408 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
2409 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2410 return -1;
2411 }
Michal Vasko50576712017-07-28 12:28:33 +02002412
2413 /* but if the module is the same as the parent, it should have been omitted */
2414 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
2415 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2416 return -1;
2417 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002418 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002419 /* no module, so it must be the same as the list (parent) */
2420 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002421 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2422 return -1;
2423 }
2424 }
2425
Michal Vasko9ba34de2016-12-07 12:21:19 +01002426 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002427 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002428 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2429 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002430 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2431 } else {
2432 key_val = key->value_str;
2433 }
2434
Michal Vasko22448d32016-03-16 13:17:29 +01002435 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002436 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002437 return 1;
2438 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002439
2440 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002441 }
2442
2443 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002444 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002445 return -1;
2446 }
2447
2448 return 0;
2449}
2450
Radek Krejci45826012016-08-24 15:07:57 +02002451/**
2452 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2453 *
2454 * @param[in] nodeid Node data path to find
2455 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2456 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2457 * @param[out] parsed Number of characters processed in \p id
2458 * @return The closes parent (or the node itself) from the path
2459 */
Michal Vasko22448d32016-03-16 13:17:29 +01002460struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002461resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2462 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002463{
Michal Vasko10728b52016-04-07 14:26:29 +02002464 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002465 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002466 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002467 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002468 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002469 struct lyd_node_leaf_list *llist;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002470 const struct lys_module *prefix_mod, *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002471 struct ly_ctx *ctx;
2472
2473 assert(nodeid && start && parsed);
2474
2475 ctx = start->schema->module->ctx;
2476 id = nodeid;
2477
Michal Vasko50576712017-07-28 12:28:33 +02002478 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002479 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002480 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002481 return NULL;
2482 }
2483 id += r;
2484 /* add it to parsed only after the data node was actually found */
2485 last_parsed = r;
2486
2487 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002488 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002489 start = start->child;
2490 } else {
2491 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002492 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002493 }
2494
2495 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002496 list_instance_position = 0;
2497
Michal Vasko22448d32016-03-16 13:17:29 +01002498 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002499 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002500 if (lys_parent(sibling->schema)) {
2501 if (options & LYD_PATH_OPT_OUTPUT) {
2502 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002503 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002504 *parsed = -1;
2505 return NULL;
2506 }
2507 } else {
2508 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002509 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002510 *parsed = -1;
2511 return NULL;
2512 }
2513 }
2514 }
2515
Michal Vasko22448d32016-03-16 13:17:29 +01002516 /* name match */
2517 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2518
2519 /* module check */
2520 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002521 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002522 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002523 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002524 return NULL;
2525 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002526
2527 if (ly_buf_used && module_name[0]) {
2528 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2529 }
2530 ly_buf_used++;
2531
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002532 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002533 module_name[mod_name_len] = '\0';
2534 /* will also find an augment module */
2535 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002536
2537 if (buf_backup) {
2538 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002539 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002540 free(buf_backup);
2541 buf_backup = NULL;
2542 }
2543 ly_buf_used--;
2544
Michal Vasko22448d32016-03-16 13:17:29 +01002545 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002546 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2547 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2548 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002549 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002550 return NULL;
2551 }
2552 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002553 prefix_mod = prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002554 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002555 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002556 continue;
2557 }
2558
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002559 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002560 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002561 llist = (struct lyd_node_leaf_list *)sibling;
2562
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002563 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002564 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002565 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2566 &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002567 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2568 *parsed = -1;
2569 return NULL;
2570 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002571 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2572 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2573 *parsed = -1;
2574 return NULL;
2575 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002576 } else {
2577 r = 0;
2578 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002579 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002580 }
2581 }
2582
Michal Vasko21b90ce2017-09-19 09:38:27 +02002583 /* make value canonical (remove module name prefix) unless it was specified with it */
2584 if (!strchr(llist_value, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002585 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2586 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002587 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2588 } else {
2589 data_val = llist->value_str;
2590 }
2591
2592 if ((!llist_value && data_val && data_val[0])
2593 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002594 continue;
2595 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002596
Michal Vaskof0a50972016-10-19 11:33:55 +02002597 id += r;
2598 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002599 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002600
Radek Krejci45826012016-08-24 15:07:57 +02002601 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002602 /* 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 +01002603 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002604 /* none match */
2605 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002606 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002607
2608 ++list_instance_position;
2609 r = 0;
Michal Vasko50576712017-07-28 12:28:33 +02002610 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002611 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002612 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002613 return NULL;
2614 } else if (ret == 1) {
2615 /* this list instance does not match */
2616 continue;
2617 }
2618 id += r;
2619 last_parsed += r;
2620 }
2621
2622 *parsed += last_parsed;
2623
2624 /* the result node? */
2625 if (!id[0]) {
2626 return sibling;
2627 }
2628
2629 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002630 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002631 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002632 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002633 return NULL;
2634 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002635 last_match = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002636 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002637 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002638 break;
2639 }
2640 }
2641
2642 /* no match, return last match */
2643 if (!sibling) {
2644 return last_match;
2645 }
2646
Michal Vasko50576712017-07-28 12:28:33 +02002647 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002648 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002649 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002650 return NULL;
2651 }
2652 id += r;
2653 last_parsed = r;
2654 }
2655
2656 /* cannot get here */
2657 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002658 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002659 return NULL;
2660}
2661
Michal Vasko3edeaf72016-02-11 13:17:43 +01002662/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002663 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002664 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002665 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002666 * @param[in] str_restr Restriction as a string.
2667 * @param[in] type Type of the restriction.
2668 * @param[out] ret Final interval structure that starts with
2669 * the interval of the initial type, continues with intervals
2670 * of any superior types derived from the initial one, and
2671 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002672 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002673 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002674 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002675int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002676resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002677{
2678 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002679 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002680 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002681 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002682 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002683 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002684 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002685
2686 switch (type->base) {
2687 case LY_TYPE_BINARY:
2688 kind = 0;
2689 local_umin = 0;
2690 local_umax = 18446744073709551615UL;
2691
2692 if (!str_restr && type->info.binary.length) {
2693 str_restr = type->info.binary.length->expr;
2694 }
2695 break;
2696 case LY_TYPE_DEC64:
2697 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002698 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2699 local_fmax = __INT64_C(9223372036854775807);
2700 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002701
2702 if (!str_restr && type->info.dec64.range) {
2703 str_restr = type->info.dec64.range->expr;
2704 }
2705 break;
2706 case LY_TYPE_INT8:
2707 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002708 local_smin = __INT64_C(-128);
2709 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002710
2711 if (!str_restr && type->info.num.range) {
2712 str_restr = type->info.num.range->expr;
2713 }
2714 break;
2715 case LY_TYPE_INT16:
2716 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002717 local_smin = __INT64_C(-32768);
2718 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002719
2720 if (!str_restr && type->info.num.range) {
2721 str_restr = type->info.num.range->expr;
2722 }
2723 break;
2724 case LY_TYPE_INT32:
2725 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002726 local_smin = __INT64_C(-2147483648);
2727 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002728
2729 if (!str_restr && type->info.num.range) {
2730 str_restr = type->info.num.range->expr;
2731 }
2732 break;
2733 case LY_TYPE_INT64:
2734 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002735 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2736 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002737
2738 if (!str_restr && type->info.num.range) {
2739 str_restr = type->info.num.range->expr;
2740 }
2741 break;
2742 case LY_TYPE_UINT8:
2743 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002744 local_umin = __UINT64_C(0);
2745 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002746
2747 if (!str_restr && type->info.num.range) {
2748 str_restr = type->info.num.range->expr;
2749 }
2750 break;
2751 case LY_TYPE_UINT16:
2752 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002753 local_umin = __UINT64_C(0);
2754 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002755
2756 if (!str_restr && type->info.num.range) {
2757 str_restr = type->info.num.range->expr;
2758 }
2759 break;
2760 case LY_TYPE_UINT32:
2761 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002762 local_umin = __UINT64_C(0);
2763 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002764
2765 if (!str_restr && type->info.num.range) {
2766 str_restr = type->info.num.range->expr;
2767 }
2768 break;
2769 case LY_TYPE_UINT64:
2770 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002771 local_umin = __UINT64_C(0);
2772 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002773
2774 if (!str_restr && type->info.num.range) {
2775 str_restr = type->info.num.range->expr;
2776 }
2777 break;
2778 case LY_TYPE_STRING:
2779 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002780 local_umin = __UINT64_C(0);
2781 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002782
2783 if (!str_restr && type->info.str.length) {
2784 str_restr = type->info.str.length->expr;
2785 }
2786 break;
2787 default:
2788 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002789 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002790 }
2791
2792 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002793 if (type->der) {
2794 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002795 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002796 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002797 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002798 assert(!intv || (intv->kind == kind));
2799 }
2800
2801 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002802 /* we do not have any restriction, return superior ones */
2803 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002804 return EXIT_SUCCESS;
2805 }
2806
2807 /* adjust local min and max */
2808 if (intv) {
2809 tmp_intv = intv;
2810
2811 if (kind == 0) {
2812 local_umin = tmp_intv->value.uval.min;
2813 } else if (kind == 1) {
2814 local_smin = tmp_intv->value.sval.min;
2815 } else if (kind == 2) {
2816 local_fmin = tmp_intv->value.fval.min;
2817 }
2818
2819 while (tmp_intv->next) {
2820 tmp_intv = tmp_intv->next;
2821 }
2822
2823 if (kind == 0) {
2824 local_umax = tmp_intv->value.uval.max;
2825 } else if (kind == 1) {
2826 local_smax = tmp_intv->value.sval.max;
2827 } else if (kind == 2) {
2828 local_fmax = tmp_intv->value.fval.max;
2829 }
2830 }
2831
2832 /* finally parse our restriction */
2833 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002834 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002836 if (!tmp_local_intv) {
2837 assert(!local_intv);
2838 local_intv = malloc(sizeof *local_intv);
2839 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002840 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002841 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002842 tmp_local_intv = tmp_local_intv->next;
2843 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02002844 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM, error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002845
2846 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002847 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002848 tmp_local_intv->next = NULL;
2849
2850 /* min */
2851 ptr = seg_ptr;
2852 while (isspace(ptr[0])) {
2853 ++ptr;
2854 }
2855 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2856 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002857 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002858 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002859 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002860 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002861 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2862 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2863 goto error;
2864 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002865 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002866 } else if (!strncmp(ptr, "min", 3)) {
2867 if (kind == 0) {
2868 tmp_local_intv->value.uval.min = local_umin;
2869 } else if (kind == 1) {
2870 tmp_local_intv->value.sval.min = local_smin;
2871 } else if (kind == 2) {
2872 tmp_local_intv->value.fval.min = local_fmin;
2873 }
2874
2875 ptr += 3;
2876 } else if (!strncmp(ptr, "max", 3)) {
2877 if (kind == 0) {
2878 tmp_local_intv->value.uval.min = local_umax;
2879 } else if (kind == 1) {
2880 tmp_local_intv->value.sval.min = local_smax;
2881 } else if (kind == 2) {
2882 tmp_local_intv->value.fval.min = local_fmax;
2883 }
2884
2885 ptr += 3;
2886 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002887 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002888 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002889 }
2890
2891 while (isspace(ptr[0])) {
2892 ptr++;
2893 }
2894
2895 /* no interval or interval */
2896 if ((ptr[0] == '|') || !ptr[0]) {
2897 if (kind == 0) {
2898 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2899 } else if (kind == 1) {
2900 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2901 } else if (kind == 2) {
2902 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2903 }
2904 } else if (!strncmp(ptr, "..", 2)) {
2905 /* skip ".." */
2906 ptr += 2;
2907 while (isspace(ptr[0])) {
2908 ++ptr;
2909 }
2910
2911 /* max */
2912 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2913 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002914 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002915 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002916 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002917 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002918 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2919 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2920 goto error;
2921 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002922 }
2923 } else if (!strncmp(ptr, "max", 3)) {
2924 if (kind == 0) {
2925 tmp_local_intv->value.uval.max = local_umax;
2926 } else if (kind == 1) {
2927 tmp_local_intv->value.sval.max = local_smax;
2928 } else if (kind == 2) {
2929 tmp_local_intv->value.fval.max = local_fmax;
2930 }
2931 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002932 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002933 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002934 }
2935 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002936 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002937 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002938 }
2939
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002940 /* check min and max in correct order*/
2941 if (kind == 0) {
2942 /* current segment */
2943 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2944 goto error;
2945 }
2946 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2947 goto error;
2948 }
2949 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002950 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002951 goto error;
2952 }
2953 } else if (kind == 1) {
2954 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2955 goto error;
2956 }
2957 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2958 goto error;
2959 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002960 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002961 goto error;
2962 }
2963 } else if (kind == 2) {
2964 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2965 goto error;
2966 }
2967 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2968 goto error;
2969 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002970 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002971 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002972 goto error;
2973 }
2974 }
2975
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002976 /* next segment (next OR) */
2977 seg_ptr = strchr(seg_ptr, '|');
2978 if (!seg_ptr) {
2979 break;
2980 }
2981 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002982 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002983 }
2984
2985 /* check local restrictions against superior ones */
2986 if (intv) {
2987 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002988 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002989
2990 while (tmp_local_intv && tmp_intv) {
2991 /* reuse local variables */
2992 if (kind == 0) {
2993 local_umin = tmp_local_intv->value.uval.min;
2994 local_umax = tmp_local_intv->value.uval.max;
2995
2996 /* it must be in this interval */
2997 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2998 /* this interval is covered, next one */
2999 if (local_umax <= tmp_intv->value.uval.max) {
3000 tmp_local_intv = tmp_local_intv->next;
3001 continue;
3002 /* ascending order of restrictions -> fail */
3003 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003004 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003005 }
3006 }
3007 } else if (kind == 1) {
3008 local_smin = tmp_local_intv->value.sval.min;
3009 local_smax = tmp_local_intv->value.sval.max;
3010
3011 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3012 if (local_smax <= tmp_intv->value.sval.max) {
3013 tmp_local_intv = tmp_local_intv->next;
3014 continue;
3015 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003016 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003017 }
3018 }
3019 } else if (kind == 2) {
3020 local_fmin = tmp_local_intv->value.fval.min;
3021 local_fmax = tmp_local_intv->value.fval.max;
3022
Michal Vasko4d1f0482016-09-19 14:35:06 +02003023 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003024 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003025 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003026 tmp_local_intv = tmp_local_intv->next;
3027 continue;
3028 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003029 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003030 }
3031 }
3032 }
3033
3034 tmp_intv = tmp_intv->next;
3035 }
3036
3037 /* some interval left uncovered -> fail */
3038 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003039 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003040 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003041 }
3042
Michal Vaskoaeb51802016-04-11 10:58:47 +02003043 /* append the local intervals to all the intervals of the superior types, return it all */
3044 if (intv) {
3045 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3046 tmp_intv->next = local_intv;
3047 } else {
3048 intv = local_intv;
3049 }
3050 *ret = intv;
3051
3052 return EXIT_SUCCESS;
3053
3054error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003055 while (intv) {
3056 tmp_intv = intv->next;
3057 free(intv);
3058 intv = tmp_intv;
3059 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003060 while (local_intv) {
3061 tmp_local_intv = local_intv->next;
3062 free(local_intv);
3063 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003064 }
3065
Michal Vaskoaeb51802016-04-11 10:58:47 +02003066 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003067}
3068
Michal Vasko730dfdf2015-08-11 14:48:05 +02003069/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003070 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3071 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003072 *
3073 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003074 * @param[in] mod_name Typedef name module name.
3075 * @param[in] module Main module.
3076 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003077 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003078 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003079 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003080 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003081int
Michal Vasko1e62a092015-12-01 12:27:20 +01003082resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3083 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003084{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003085 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003086 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087 int tpdf_size;
3088
Michal Vasko1dca6882015-10-22 14:29:42 +02003089 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003090 /* no prefix, try built-in types */
3091 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003092 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003093 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003094 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003095 }
3096 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097 }
3098 }
3099 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003100 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003101 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003102 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003103 }
3104 }
3105
Michal Vasko1dca6882015-10-22 14:29:42 +02003106 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003107 /* search in local typedefs */
3108 while (parent) {
3109 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003110 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003111 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3112 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113 break;
3114
Radek Krejci76512572015-08-04 09:47:08 +02003115 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003116 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3117 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003118 break;
3119
Radek Krejci76512572015-08-04 09:47:08 +02003120 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003121 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3122 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003123 break;
3124
Radek Krejci76512572015-08-04 09:47:08 +02003125 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003126 case LYS_ACTION:
3127 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3128 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003129 break;
3130
Radek Krejci76512572015-08-04 09:47:08 +02003131 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003132 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3133 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003134 break;
3135
Radek Krejci76512572015-08-04 09:47:08 +02003136 case LYS_INPUT:
3137 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003138 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3139 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140 break;
3141
3142 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003143 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144 continue;
3145 }
3146
3147 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003148 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003149 match = &tpdf[i];
3150 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151 }
3152 }
3153
Michal Vaskodcf98e62016-05-05 17:53:53 +02003154 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155 }
Radek Krejcic071c542016-01-27 14:57:51 +01003156 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003157 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02003158 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003159 if (!module) {
3160 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003161 }
3162 }
3163
3164 /* search in top level typedefs */
3165 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003166 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003167 match = &module->tpdf[i];
3168 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003169 }
3170 }
3171
3172 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003173 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003175 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 +02003176 match = &module->inc[i].submodule->tpdf[j];
3177 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003178 }
3179 }
3180 }
3181
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003182 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003183
3184check_leafref:
3185 if (ret) {
3186 *ret = match;
3187 }
3188 if (match->type.base == LY_TYPE_LEAFREF) {
3189 while (!match->type.info.lref.path) {
3190 match = match->type.der;
3191 assert(match);
3192 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003193 }
3194 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003195}
3196
Michal Vasko1dca6882015-10-22 14:29:42 +02003197/**
3198 * @brief Check the default \p value of the \p type. Logs directly.
3199 *
3200 * @param[in] type Type definition to use.
3201 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003202 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003203 *
3204 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3205 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003206static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003207check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003208{
Radek Krejcibad2f172016-08-02 11:04:15 +02003209 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003210 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003211 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003212 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01003213 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003214
Radek Krejci51673202016-11-01 17:00:32 +01003215 assert(value);
3216
Radek Krejcic13db382016-08-16 10:52:42 +02003217 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003218 /* the type was not resolved yet, nothing to do for now */
3219 return EXIT_FAILURE;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003220 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003221 /* do not check defaults in not implemented module's data */
3222 return EXIT_SUCCESS;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003223 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003224 /* identityrefs are checked when instantiated in data instead of typedef,
3225 * but in typedef the value has to be modified to include the prefix */
3226 if (*value) {
3227 if (strchr(*value, ':')) {
3228 dflt = transform_schema2json(module, *value);
3229 } else {
3230 /* default prefix of the module where the typedef is defined */
3231 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
3232 dflt = lydict_insert_zc(module->ctx, s);
3233 }
3234 lydict_remove(module->ctx, *value);
3235 *value = dflt;
3236 }
3237 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003238 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3239 /* leafref in typedef cannot be checked */
3240 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003241 }
3242
Radek Krejci51673202016-11-01 17:00:32 +01003243 dflt = *value;
3244 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003245 /* we do not have a new default value, so is there any to check even, in some base type? */
3246 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3247 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003248 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003249 break;
3250 }
3251 }
3252
Radek Krejci51673202016-11-01 17:00:32 +01003253 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003254 /* no default value, nothing to check, all is well */
3255 return EXIT_SUCCESS;
3256 }
3257
3258 /* 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)? */
3259 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003260 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003261 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3262 return EXIT_SUCCESS;
3263 } else {
3264 /* check the default value from typedef, but use also the typedef's module
3265 * due to possible searching in imported modules which is expected in
3266 * typedef's module instead of module where the typedef is used */
3267 module = base_tpdf->module;
3268 }
3269 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003270 case LY_TYPE_INST:
3271 case LY_TYPE_LEAFREF:
3272 case LY_TYPE_BOOL:
3273 case LY_TYPE_EMPTY:
3274 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3275 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003276 case LY_TYPE_BITS:
3277 /* the default value must match the restricted list of values, if the type was restricted */
3278 if (type->info.bits.count) {
3279 break;
3280 }
3281 return EXIT_SUCCESS;
3282 case LY_TYPE_ENUM:
3283 /* the default value must match the restricted list of values, if the type was restricted */
3284 if (type->info.enums.count) {
3285 break;
3286 }
3287 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003288 case LY_TYPE_DEC64:
3289 if (type->info.dec64.range) {
3290 break;
3291 }
3292 return EXIT_SUCCESS;
3293 case LY_TYPE_BINARY:
3294 if (type->info.binary.length) {
3295 break;
3296 }
3297 return EXIT_SUCCESS;
3298 case LY_TYPE_INT8:
3299 case LY_TYPE_INT16:
3300 case LY_TYPE_INT32:
3301 case LY_TYPE_INT64:
3302 case LY_TYPE_UINT8:
3303 case LY_TYPE_UINT16:
3304 case LY_TYPE_UINT32:
3305 case LY_TYPE_UINT64:
3306 if (type->info.num.range) {
3307 break;
3308 }
3309 return EXIT_SUCCESS;
3310 case LY_TYPE_STRING:
3311 if (type->info.str.length || type->info.str.patterns) {
3312 break;
3313 }
3314 return EXIT_SUCCESS;
3315 case LY_TYPE_UNION:
3316 /* way too much trouble learning whether we need to check the default again, so just do it */
3317 break;
3318 default:
3319 LOGINT;
3320 return -1;
3321 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003322 } else if (type->base == LY_TYPE_EMPTY) {
3323 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3324 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3325 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003326 }
3327
Michal Vasko1dca6882015-10-22 14:29:42 +02003328 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003329 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003330 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003331 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003332 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Radek Krejciaa1303c2017-05-31 13:57:37 +02003333 LY_CHECK_ERR_RETURN(!node.schema, LOGMEM, -1);
Radek Krejcibad2f172016-08-02 11:04:15 +02003334 node.schema->name = strdup("fake-default");
Radek Krejciaa1303c2017-05-31 13:57:37 +02003335 LY_CHECK_ERR_RETURN(!node.schema->name, LOGMEM; free(node.schema), -1);
Michal Vasko56826402016-03-02 11:11:37 +01003336 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003337 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003338
Radek Krejci37b756f2016-01-18 10:15:03 +01003339 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003340 if (!type->info.lref.target) {
3341 ret = EXIT_FAILURE;
3342 goto finish;
3343 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003344 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003345 if (!ret) {
3346 /* adopt possibly changed default value to its canonical form */
3347 if (*value) {
3348 *value = dflt;
3349 }
3350 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003351 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003352 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 +01003353 /* possible forward reference */
3354 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003355 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003356 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003357 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3358 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3359 /* we have refined bits/enums */
3360 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3361 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003362 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003363 }
3364 }
Radek Krejci51673202016-11-01 17:00:32 +01003365 } else {
3366 /* success - adopt canonical form from the node into the default value */
3367 if (dflt != node.value_str) {
3368 /* this can happen only if we have non-inherited default value,
3369 * inherited default values are already in canonical form */
3370 assert(dflt == *value);
3371 *value = node.value_str;
3372 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003373 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003374 }
3375
3376finish:
3377 if (node.value_type == LY_TYPE_BITS) {
3378 free(node.value.bit);
3379 }
3380 free((char *)node.schema->name);
3381 free(node.schema);
3382
3383 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384}
3385
Michal Vasko730dfdf2015-08-11 14:48:05 +02003386/**
3387 * @brief Check a key for mandatory attributes. Logs directly.
3388 *
3389 * @param[in] key The key to check.
3390 * @param[in] flags What flags to check.
3391 * @param[in] list The list of all the keys.
3392 * @param[in] index Index of the key in the key list.
3393 * @param[in] name The name of the keys.
3394 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003395 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003396 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003397 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003398static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003399check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400{
Radek Krejciadb57612016-02-16 13:34:34 +01003401 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 char *dup = NULL;
3403 int j;
3404
3405 /* existence */
3406 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003407 if (name[len] != '\0') {
3408 dup = strdup(name);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003409 LY_CHECK_ERR_RETURN(!dup, LOGMEM, -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003410 dup[len] = '\0';
3411 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003413 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003414 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003415 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003416 }
3417
3418 /* uniqueness */
3419 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003420 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003421 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003422 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 }
3424 }
3425
3426 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003427 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003428 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003429 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003430 }
3431
3432 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003433 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003434 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003435 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003436 }
3437
3438 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003439 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003440 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003441 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003442 }
3443
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003444 /* key is not placed from augment */
3445 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003446 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003447 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003448 return -1;
3449 }
3450
Radek Krejci3f21ada2016-08-01 13:34:31 +02003451 /* key is not when/if-feature -conditional */
3452 j = 0;
3453 if (key->when || (key->iffeature_size && (j = 1))) {
3454 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003455 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003456 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003457 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003458 }
3459
Michal Vasko0b85aa82016-03-07 14:37:43 +01003460 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003461}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003462
3463/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003464 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003465 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003466 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003467 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468 *
3469 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3470 */
3471int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003472resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003473{
Radek Krejci581ce772015-11-10 17:22:40 +01003474 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003475 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476
Michal Vaskodc300b02017-04-07 14:09:20 +02003477 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003478 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003479 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003480 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003481 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003482 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003483 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003484 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003485 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003486 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003487 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003488 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003489 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003490 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 }
Radek Krejci581ce772015-11-10 17:22:40 +01003492 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003493 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003494 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003495 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003496 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003497 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498 }
3499
Radek Krejcicf509982015-12-15 09:22:44 +01003500 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003501 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3502 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003503 return -1;
3504 }
3505
Radek Krejcid09d1a52016-08-11 14:05:45 +02003506 /* check that all unique's targets are of the same config type */
3507 if (*trg_type) {
3508 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3509 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003510 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003511 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3512 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3513 return -1;
3514 }
3515 } else {
3516 /* first unique */
3517 if (leaf->flags & LYS_CONFIG_W) {
3518 *trg_type = 1;
3519 } else {
3520 *trg_type = 2;
3521 }
3522 }
3523
Radek Krejcica7efb72016-01-18 13:06:01 +01003524 /* set leaf's unique flag */
3525 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3526
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003527 return EXIT_SUCCESS;
3528
3529error:
3530
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003531 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003532}
3533
Radek Krejci0c0086a2016-03-24 15:20:28 +01003534void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003535unres_data_del(struct unres_data *unres, uint32_t i)
3536{
3537 /* there are items after the one deleted */
3538 if (i+1 < unres->count) {
3539 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003540 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003541
3542 /* deleting the last item */
3543 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003544 free(unres->node);
3545 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 }
3547
3548 /* if there are no items after and it is not the last one, just move the counter */
3549 --unres->count;
3550}
3551
Michal Vasko0491ab32015-08-19 14:28:29 +02003552/**
3553 * @brief Resolve (find) a data node from a specific module. Does not log.
3554 *
3555 * @param[in] mod Module to search in.
3556 * @param[in] name Name of the data node.
3557 * @param[in] nam_len Length of the name.
3558 * @param[in] start Data node to start the search from.
3559 * @param[in,out] parents Resolved nodes. If there are some parents,
3560 * they are replaced (!!) with the resolvents.
3561 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003562 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003563 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003565resolve_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 +02003566{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003567 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003568 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003569 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 if (!parents->count) {
3572 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003573 parents->node = malloc(sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003574 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003575 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003577 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003578 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003579 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003580 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003581 continue;
3582 }
3583 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003584 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003585 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 && node->schema->name[nam_len] == '\0') {
3587 /* matching target */
3588 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003589 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003590 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003591 flag = 1;
3592 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003593 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003594 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003595 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Radek Krejciaa1303c2017-05-31 13:57:37 +02003596 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003597 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003598 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003599 }
3600 }
3601 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003602
3603 if (!flag) {
3604 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003605 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003606 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003607 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003608 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609 }
3610
Michal Vasko0491ab32015-08-19 14:28:29 +02003611 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003612}
3613
Michal Vaskoe27516a2016-10-10 17:55:31 +00003614static int
Michal Vasko1c007172017-03-10 10:20:44 +01003615resolve_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 +00003616{
3617 int dep1, dep2;
3618 const struct lys_node *node;
3619
3620 if (lys_parent(op_node)) {
3621 /* inner operation (notif/action) */
3622 if (abs_path) {
3623 return 1;
3624 } else {
3625 /* compare depth of both nodes */
3626 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3627 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3628 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3629 return 1;
3630 }
3631 }
3632 } else {
3633 /* top-level operation (notif/rpc) */
3634 if (op_node != first_node) {
3635 return 1;
3636 }
3637 }
3638
3639 return 0;
3640}
3641
Michal Vasko730dfdf2015-08-11 14:48:05 +02003642/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003643 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003644 *
Michal Vaskobb211122015-08-19 14:03:11 +02003645 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003646 * @param[in] context_node Predicate context node (where the predicate is placed).
3647 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003648 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003649 *
Michal Vasko184521f2015-09-24 13:14:26 +02003650 * @return 0 on forward reference, otherwise the number
3651 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003652 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003653 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003654static int
Michal Vasko1c007172017-03-10 10:20:44 +01003655resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3656 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003657{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003658 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003659 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003660 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003661 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3662 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003663
3664 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003665 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003666 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003667 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003668 return -parsed+i;
3669 }
3670 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003671 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003672
Michal Vasko58090902015-08-13 14:04:15 +02003673 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003674 if (sour_pref) {
3675 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3676 } else {
3677 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003678 }
Michal Vaskobb520442017-05-23 10:55:18 +02003679 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003680 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003681 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003682 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003683 }
3684
3685 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003686 dest_parent_times = 0;
3687 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003688 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3689 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003690 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 +02003691 return -parsed;
3692 }
3693 pke_parsed += i;
3694
Radek Krejciadb57612016-02-16 13:34:34 +01003695 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003696 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3697 && !((struct lys_node_augment *)dst_node->parent)->target) {
3698 /* we are in an unresolved augment, cannot evaluate */
3699 LOGVAL(LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
3700 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3701 return 0;
3702 }
3703
Michal Vaskofbaead72016-10-07 10:54:48 +02003704 /* path is supposed to be evaluated in data tree, so we have to skip
3705 * all schema nodes that cannot be instantiated in data tree */
3706 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003707 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003708 dst_node = lys_parent(dst_node));
3709
Michal Vasko1f76a282015-08-04 16:16:53 +02003710 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003711 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003712 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003713 }
3714 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003715 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003716 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003717 if (dest_pref) {
3718 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3719 } else {
3720 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003721 }
Michal Vaskobb520442017-05-23 10:55:18 +02003722 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 +02003723 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003724 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003725 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003726 }
3727
Michal Vaskoe27516a2016-10-10 17:55:31 +00003728 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003729 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003730 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003731 }
3732 first_iter = 0;
3733 }
3734
Michal Vasko1f76a282015-08-04 16:16:53 +02003735 if (pke_len == pke_parsed) {
3736 break;
3737 }
3738
Michal Vaskobb520442017-05-23 10:55:18 +02003739 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 +02003740 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003741 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003742 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003743 return -parsed;
3744 }
3745 pke_parsed += i;
3746 }
3747
3748 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003749 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003750 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003751 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003752 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003753 return -parsed;
3754 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003755 } while (has_predicate);
3756
3757 return parsed;
3758}
3759
Michal Vasko730dfdf2015-08-11 14:48:05 +02003760/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003761 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003762 *
Michal Vaskobb211122015-08-19 14:03:11 +02003763 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003764 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003765 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003766 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003767 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003768 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003769static int
Michal Vasko1c007172017-03-10 10:20:44 +01003770resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003771{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003772 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003773 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003774 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02003775 const char *id, *prefix, *name;
3776 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003777 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003778
Michal Vasko184521f2015-09-24 13:14:26 +02003779 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003780 parent_times = 0;
3781 id = path;
3782
Michal Vasko1c007172017-03-10 10:20:44 +01003783 /* find operation schema we are in */
3784 for (op_node = lys_parent(parent);
3785 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3786 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003787
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003788 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003790 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko1c007172017-03-10 10:20:44 +01003791 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003792 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003793 }
3794 id += i;
3795
Michal Vaskobb520442017-05-23 10:55:18 +02003796 /* get the current module */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003797 tmp_mod = prefix ? lys_get_import_module(cur_module, NULL, 0, prefix, pref_len) : cur_module;
3798 if (!tmp_mod) {
Michal Vaskobb520442017-05-23 10:55:18 +02003799 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3800 return EXIT_FAILURE;
3801 }
3802 last_aug = NULL;
3803
Michal Vasko184521f2015-09-24 13:14:26 +02003804 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003805 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003806 /* use module data */
3807 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003808
Michal Vasko1f76a282015-08-04 16:16:53 +02003809 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003810 /* we are looking for the right parent */
3811 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003812 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
3813 && !((struct lys_node_augment *)node->parent)->target) {
3814 /* we are in an unresolved augment, cannot evaluate */
3815 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node->parent,
3816 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
3817 return EXIT_FAILURE;
3818 }
3819
Radek Krejci3a5501d2016-07-18 22:03:34 +02003820 /* path is supposed to be evaluated in data tree, so we have to skip
3821 * all schema nodes that cannot be instantiated in data tree */
3822 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003823 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003824 node = lys_parent(node));
3825
Michal Vasko1f76a282015-08-04 16:16:53 +02003826 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003827 if (i == parent_times - 1) {
3828 /* top-level */
3829 break;
3830 }
3831
3832 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003833 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003834 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003835 }
3836 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003837 } else {
3838 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003839 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003840 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003841 }
3842
Michal Vaskobb520442017-05-23 10:55:18 +02003843 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3844 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003845 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003846get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003847 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02003848 }
3849
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003850 rc = lys_getnext_data(tmp_mod, (last_aug ? (struct lys_node *)last_aug : node), name, nam_len, LYS_LIST
Michal Vaskobb520442017-05-23 10:55:18 +02003851 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003852 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003853 if (last_aug) {
3854 goto get_next_augment;
3855 }
Michal Vasko1c007172017-03-10 10:20:44 +01003856 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003857 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003858 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003859
Michal Vaskoe27516a2016-10-10 17:55:31 +00003860 if (first_iter) {
3861 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003862 if (op_node && parent_times &&
3863 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003864 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003865 }
3866 first_iter = 0;
3867 }
3868
Michal Vasko1f76a282015-08-04 16:16:53 +02003869 if (has_predicate) {
3870 /* we have predicate, so the current result must be list */
3871 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003872 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003873 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003874 }
3875
Michal Vasko1c007172017-03-10 10:20:44 +01003876 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003877 if (!i) {
3878 return EXIT_FAILURE;
3879 } else if (i < 0) {
3880 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003881 }
3882 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003883 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003884 }
3885 } while (id[0]);
3886
Michal Vaskoca917682016-07-25 11:00:37 +02003887 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003888 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003889 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003890 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 +02003891 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003892 }
3893
Radek Krejcicf509982015-12-15 09:22:44 +01003894 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003895 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003896 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003897 return -1;
3898 }
3899
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003900 if (ret) {
3901 *ret = node;
3902 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003903
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003904 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003905}
3906
Michal Vasko730dfdf2015-08-11 14:48:05 +02003907/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003908 * @brief Resolve instance-identifier predicate in JSON data format.
3909 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003910 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02003911 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02003912 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003913 * @param[in,out] node Node matching the restriction without
3914 * the predicate. If it does not satisfy the predicate,
3915 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003916 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003917 * @return Number of characters successfully parsed,
3918 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003919 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003920static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003921resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct lyd_node **node, int cur_idx)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003922{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003923 /* ... /node[key=value] ... */
3924 struct lyd_node_leaf_list *key;
3925 struct lys_node_leaf **list_keys = NULL;
3926 struct lys_node_list *slist;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003927 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003928 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003929
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003930 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02003931
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003932 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003933 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003934 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
3935 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003936 }
3937 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003938
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003939 /* target */
3940 if (name[0] == '.') {
3941 /* leaf-list value */
3942 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
3943 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
3944 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3945 parsed = -1;
3946 goto cleanup;
3947 }
3948
3949 /* check the value */
3950 if (strncmp(((struct lyd_node_leaf_list *)*node)->value_str, value, val_len)
3951 || ((struct lyd_node_leaf_list *)*node)->value_str[val_len]) {
3952 *node = NULL;
3953 goto cleanup;
3954 }
3955
3956 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003957 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003958
3959 /* keyless list position */
3960 if ((*node)->schema->nodetype != LYS_LIST) {
3961 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
3962 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3963 parsed = -1;
3964 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003965 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003966
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003967 if (((struct lys_node_list *)(*node)->schema)->keys) {
3968 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
3969 (*node)->schema->name);
3970 parsed = -1;
3971 goto cleanup;
3972 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003973
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003974 /* check the index */
3975 if (atoi(name) != cur_idx) {
3976 *node = NULL;
3977 goto cleanup;
3978 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003979
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003980 } else {
3981 /* list key value */
3982 if ((*node)->schema->nodetype != LYS_LIST) {
3983 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
3984 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3985 parsed = -1;
3986 goto cleanup;
3987 }
3988 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003989
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003990 /* prepare key array */
3991 if (!list_keys) {
3992 list_keys = malloc(slist->keys_size * sizeof *list_keys);
3993 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM, -1);
3994 for (i = 0; i < slist->keys_size; ++i) {
3995 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02003996 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003997 }
3998
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003999 /* find the schema key leaf */
4000 for (i = 0; i < slist->keys_size; ++i) {
4001 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4002 break;
4003 }
4004 }
4005 if (i == slist->keys_size) {
4006 /* this list has no such key */
4007 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
4008 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4009 parsed = -1;
4010 goto cleanup;
4011 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004012
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004013 /* check module */
4014 if (model) {
4015 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
4016 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
4017 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4018 parsed = -1;
4019 goto cleanup;
4020 }
4021 } else {
4022 if (list_keys[i]->module != prev_mod) {
4023 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
4024 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4025 parsed = -1;
4026 goto cleanup;
4027 }
4028 }
4029
4030 /* find the actual data key */
4031 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4032 if (key->schema == (struct lys_node *)list_keys[i]) {
4033 break;
4034 }
4035 }
4036 if (!key) {
4037 /* list instance is missing a key? definitely should not happen */
4038 LOGINT;
4039 parsed = -1;
4040 goto cleanup;
4041 }
4042
4043 /* check the value */
4044 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
4045 *node = NULL;
4046 goto cleanup;
4047 }
4048
4049 /* everything is fine, mark this key as resolved */
4050 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051 }
4052 } while (has_predicate);
4053
Michal Vaskob2f40be2016-09-08 16:03:48 +02004054 /* check that all list keys were specified */
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004055 if (list_keys) {
4056 for (i = 0; i < slist->keys_size; ++i) {
4057 if (list_keys[i]) {
4058 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
4059 parsed = -1;
4060 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004061 }
4062 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004063 }
4064
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004065cleanup:
4066 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004067 return parsed;
4068}
4069
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004070int
Michal Vaskof96dfb62017-08-17 12:23:49 +02004071lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004072{
Michal Vasko0b963112017-08-11 12:45:36 +02004073 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004074 struct lyxp_set set;
Michal Vasko769f8032017-01-24 13:11:55 +01004075 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004076
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004077 if (check_place) {
4078 parent = node;
4079 while (parent) {
4080 if (parent->nodetype == LYS_GROUPING) {
4081 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004082 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004083 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004084 if (parent->nodetype == LYS_AUGMENT) {
4085 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004086 /* unresolved augment, skip for now (will be checked later) */
4087 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004088 } else {
4089 parent = ((struct lys_node_augment *)parent)->target;
4090 continue;
4091 }
4092 }
4093 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004094 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004095 }
4096
Michal Vaskof96dfb62017-08-17 12:23:49 +02004097 ret = lyxp_node_atomize(node, &set, 1);
Michal Vasko769f8032017-01-24 13:11:55 +01004098 if (ret == -1) {
4099 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004100 }
4101
Michal Vasko9e635ac2016-10-17 11:44:09 +02004102 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004103 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004104}
4105
Radek Krejcif71f48f2016-10-25 16:37:24 +02004106static int
4107check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4108{
Radek Krejcidce5f972017-09-12 15:47:49 +02004109 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004110
4111 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004112 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4113 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004114 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 +02004115 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4116 return -1;
4117 }
4118 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4119 * of leafref resolving (lys_leaf_add_leafref_target()) */
4120 } else if (type->base == LY_TYPE_UNION) {
4121 for (i = 0; i < type->info.uni.count; i++) {
4122 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4123 return -1;
4124 }
4125 }
4126 }
4127 return 0;
4128}
4129
Michal Vasko9e635ac2016-10-17 11:44:09 +02004130/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004131 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004132 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004133 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004134 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004135 * @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 +02004136 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004137 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004138 *
4139 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004140 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004141int
4142inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004143{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004144 struct lys_node_leaf *leaf;
4145
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004146 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004147 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004148 if (clear) {
4149 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004150 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004151 } else {
4152 if (node->flags & LYS_CONFIG_SET) {
4153 /* skip nodes with an explicit config value */
4154 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4155 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004156 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004157 return -1;
4158 }
4159 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004160 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004161
4162 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4163 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4164 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004165 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4166 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004167 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4168 return -1;
4169 }
4170 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004171 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004172 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004173 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004174 return -1;
4175 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004176 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4177 leaf = (struct lys_node_leaf *)node;
4178 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004179 return -1;
4180 }
4181 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004182 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004183
4184 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004185}
4186
Michal Vasko730dfdf2015-08-11 14:48:05 +02004187/**
Michal Vasko7178e692016-02-12 15:58:05 +01004188 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004189 *
Michal Vaskobb211122015-08-19 14:03:11 +02004190 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004191 * @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 +01004192 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004193 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004194 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004195 */
Michal Vasko7178e692016-02-12 15:58:05 +01004196static int
Radek Krejcib3142312016-11-09 11:04:12 +01004197resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004198{
Michal Vasko44ab1462017-05-18 13:18:36 +02004199 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004200 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004201 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004202 struct ly_set *set;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004203
Michal Vasko2ef7db62017-06-12 09:24:02 +02004204 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004205 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004206
Michal Vaskobb520442017-05-23 10:55:18 +02004207 /* set it as not applied for now */
4208 aug->flags |= LYS_NOTAPPLIED;
4209
Michal Vasko2ef7db62017-06-12 09:24:02 +02004210 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004211 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004212 /* resolve target node */
Michal Vasko50576712017-07-28 12:28:33 +02004213 rc = resolve_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004214 if (rc == -1) {
Michal Vasko50576712017-07-28 12:28:33 +02004215 LOGVAL(LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004216 return -1;
4217 }
Michal Vasko50576712017-07-28 12:28:33 +02004218 if (!set) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004219 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4220 return EXIT_FAILURE;
4221 }
Michal Vasko50576712017-07-28 12:28:33 +02004222 aug->target = set->set.s[0];
4223 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004224 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004225
Michal Vaskod58d5962016-03-02 14:29:41 +01004226 /* check for mandatory nodes - if the target node is in another module
4227 * the added nodes cannot be mandatory
4228 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004229 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4230 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004231 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004232 }
4233
Michal Vasko07e89ef2016-03-03 13:28:57 +01004234 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004235 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004236 LY_TREE_FOR(aug->child, sub) {
4237 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4238 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4239 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4240 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004241 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004242 return -1;
4243 }
4244 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004245 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004246 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004247 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004248 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004249 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004250 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004251 return -1;
4252 }
4253 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004254 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004255 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004256 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004257 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004258 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004259 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004260 return -1;
4261 }
4262 }
4263 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004264 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004265 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004266 return -1;
4267 }
4268
Radek Krejcic071c542016-01-27 14:57:51 +01004269 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004270 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004271 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004272 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004273 }
4274 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004275
Michal Vasko44ab1462017-05-18 13:18:36 +02004276 if (!aug->child) {
4277 /* empty augment, nothing to connect, but it is techincally applied */
4278 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4279 aug->flags &= ~LYS_NOTAPPLIED;
4280 } else if (mod->implemented && apply_aug(aug, unres)) {
4281 /* we tried to connect it, we failed */
4282 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004283 }
4284
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004285 return EXIT_SUCCESS;
4286}
4287
Radek Krejcie534c132016-11-23 13:32:31 +01004288static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004289resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004290{
4291 enum LY_VLOG_ELEM vlog_type;
4292 void *vlog_node;
4293 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004294 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004295 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004296 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004297 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004298 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004299 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004300
4301 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004302 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004303 vlog_node = info->parent;
4304 vlog_type = LY_VLOG_LYS;
4305 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004306 case LYEXT_PAR_MODULE:
4307 case LYEXT_PAR_IMPORT:
4308 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004309 vlog_node = NULL;
4310 vlog_type = LY_VLOG_LYS;
4311 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004312 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004313 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004314 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004315 break;
4316 }
4317
4318 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004319 /* YIN */
4320
Radek Krejcie534c132016-11-23 13:32:31 +01004321 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004322 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004323 if (!mod) {
4324 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004325 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004326 }
4327
4328 /* find the extension definition */
4329 e = NULL;
4330 for (i = 0; i < mod->extensions_size; i++) {
4331 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4332 e = &mod->extensions[i];
4333 break;
4334 }
4335 }
4336 /* try submodules */
4337 for (j = 0; !e && j < mod->inc_size; j++) {
4338 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4339 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4340 e = &mod->inc[j].submodule->extensions[i];
4341 break;
4342 }
4343 }
4344 }
4345 if (!e) {
4346 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4347 return EXIT_FAILURE;
4348 }
4349
4350 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004351
Radek Krejci72b35992017-01-04 16:27:44 +01004352 if (e->plugin && e->plugin->check_position) {
4353 /* common part - we have plugin with position checking function, use it first */
4354 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4355 /* extension is not allowed here */
4356 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4357 return -1;
4358 }
4359 }
4360
Radek Krejci8d6b7422017-02-03 14:42:13 +01004361 /* extension type-specific part - allocation */
4362 if (e->plugin) {
4363 etype = e->plugin->type;
4364 } else {
4365 /* default type */
4366 etype = LYEXT_FLAG;
4367 }
4368 switch (etype) {
4369 case LYEXT_FLAG:
4370 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4371 break;
4372 case LYEXT_COMPLEX:
4373 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4374 break;
4375 case LYEXT_ERR:
4376 /* we never should be here */
4377 LOGINT;
4378 return -1;
4379 }
Radek Krejciaa1303c2017-05-31 13:57:37 +02004380 LY_CHECK_ERR_RETURN(!*ext, LOGMEM, -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004381
4382 /* common part for all extension types */
4383 (*ext)->def = e;
4384 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004385 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004386 (*ext)->insubstmt = info->substmt;
4387 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004388 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004389
4390 if (!(e->flags & LYS_YINELEM) && e->argument) {
4391 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4392 if (!(*ext)->arg_value) {
4393 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4394 return -1;
4395 }
4396 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4397 }
4398
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004399 (*ext)->nodetype = LYS_EXT;
4400 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004401
Radek Krejci8d6b7422017-02-03 14:42:13 +01004402 /* extension type-specific part - parsing content */
4403 switch (etype) {
4404 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004405 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4406 if (!yin->ns) {
4407 /* garbage */
4408 lyxml_free(mod->ctx, yin);
4409 continue;
4410 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4411 /* standard YANG statements are not expected here */
4412 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4413 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004414 } else if (yin->ns == info->data.yin->ns &&
4415 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004416 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004417 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004418 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004419 return -1;
4420 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004421 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004422 yin->content = NULL;
4423 lyxml_free(mod->ctx, yin);
4424 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004425 /* extension instance */
4426 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4427 LYEXT_SUBSTMT_SELF, 0, unres)) {
4428 return -1;
4429 }
Radek Krejci72b35992017-01-04 16:27:44 +01004430
Radek Krejci72b35992017-01-04 16:27:44 +01004431 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004432 }
Radek Krejci72b35992017-01-04 16:27:44 +01004433 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004434 break;
4435 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004436 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004437 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4438 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004439 return -1;
4440 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004441 break;
4442 default:
4443 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004444 }
Radek Krejci72b35992017-01-04 16:27:44 +01004445
4446 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4447
Radek Krejcie534c132016-11-23 13:32:31 +01004448 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004449 /* YANG */
4450
PavolVicanc1807262017-01-31 18:00:27 +01004451 ext_prefix = (char *)(*ext)->def;
4452 tmp = strchr(ext_prefix, ':');
4453 if (!tmp) {
4454 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004455 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004456 }
4457 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004458
PavolVicanc1807262017-01-31 18:00:27 +01004459 /* get the module where the extension is supposed to be defined */
4460 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4461 if (!mod) {
4462 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4463 return EXIT_FAILURE;
4464 }
4465
4466 /* find the extension definition */
4467 e = NULL;
4468 for (i = 0; i < mod->extensions_size; i++) {
4469 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4470 e = &mod->extensions[i];
4471 break;
4472 }
4473 }
4474 /* try submodules */
4475 for (j = 0; !e && j < mod->inc_size; j++) {
4476 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4477 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4478 e = &mod->inc[j].submodule->extensions[i];
4479 break;
4480 }
4481 }
4482 }
4483 if (!e) {
4484 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4485 return EXIT_FAILURE;
4486 }
4487
4488 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4489
4490 if (e->plugin && e->plugin->check_position) {
4491 /* common part - we have plugin with position checking function, use it first */
4492 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4493 /* extension is not allowed here */
4494 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004495 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004496 }
4497 }
4498
PavolVican22e88682017-02-14 22:38:18 +01004499 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004500 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004501 (*ext)->def = e;
4502 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004503 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004504
PavolVicanb0d84102017-02-15 16:32:42 +01004505 if (e->argument && !(*ext)->arg_value) {
4506 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4507 goto error;
4508 }
4509
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004510 (*ext)->module = info->mod;
4511 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004512
PavolVican22e88682017-02-14 22:38:18 +01004513 /* extension type-specific part */
4514 if (e->plugin) {
4515 etype = e->plugin->type;
4516 } else {
4517 /* default type */
4518 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004519 }
PavolVican22e88682017-02-14 22:38:18 +01004520 switch (etype) {
4521 case LYEXT_FLAG:
4522 /* nothing change */
4523 break;
4524 case LYEXT_COMPLEX:
4525 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004526 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM, error);
PavolVican22e88682017-02-14 22:38:18 +01004527 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4528 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004529 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004530 if (info->data.yang) {
4531 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004532 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4533 (struct lys_ext_instance_complex*)(*ext))) {
4534 goto error;
4535 }
4536 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4537 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004538 goto error;
4539 }
PavolVicana3876672017-02-21 15:49:51 +01004540 }
4541 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4542 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004543 }
PavolVican22e88682017-02-14 22:38:18 +01004544 break;
4545 case LYEXT_ERR:
4546 /* we never should be here */
4547 LOGINT;
4548 goto error;
4549 }
4550
PavolVican22e88682017-02-14 22:38:18 +01004551 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4552 goto error;
4553 }
4554 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004555 }
4556
4557 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004558error:
4559 free(ext_prefix);
4560 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004561}
4562
Michal Vasko730dfdf2015-08-11 14:48:05 +02004563/**
Pavol Vican855ca622016-09-05 13:07:54 +02004564 * @brief Resolve (find) choice default case. Does not log.
4565 *
4566 * @param[in] choic Choice to use.
4567 * @param[in] dflt Name of the default case.
4568 *
4569 * @return Pointer to the default node or NULL.
4570 */
4571static struct lys_node *
4572resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4573{
4574 struct lys_node *child, *ret;
4575
4576 LY_TREE_FOR(choic->child, child) {
4577 if (child->nodetype == LYS_USES) {
4578 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4579 if (ret) {
4580 return ret;
4581 }
4582 }
4583
4584 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004585 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004586 return child;
4587 }
4588 }
4589
4590 return NULL;
4591}
4592
4593/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004594 * @brief Resolve uses, apply augments, refines. Logs directly.
4595 *
Michal Vaskobb211122015-08-19 14:03:11 +02004596 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004597 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004598 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004599 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004600 */
Michal Vasko184521f2015-09-24 13:14:26 +02004601static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004602resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004603{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004604 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004605 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004606 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004607 struct lys_node_leaflist *llist;
4608 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004609 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004610 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004611 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004612 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004613 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004614 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004615
Michal Vasko71e1aa82015-08-12 12:17:51 +02004616 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004617
Radek Krejci93def382017-05-24 15:33:48 +02004618 /* check that the grouping is resolved (no unresolved uses inside) */
4619 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004620
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004621 if (!uses->grp->child) {
4622 /* grouping without children, warning was already displayed */
4623 return EXIT_SUCCESS;
4624 }
4625
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004626 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004627 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004628 if (node_aux->nodetype & LYS_GROUPING) {
4629 /* do not instantiate groupings from groupings */
4630 continue;
4631 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004632 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004633 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004634 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004635 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004636 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004637 }
Pavol Vican55abd332016-07-12 15:54:49 +02004638 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004639 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 +02004640 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004641 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004642 }
4643 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004644 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004645
Michal Vaskodef0db12015-10-07 13:22:48 +02004646 /* we managed to copy the grouping, the rest must be possible to resolve */
4647
Pavol Vican855ca622016-09-05 13:07:54 +02004648 if (uses->refine_size) {
4649 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004650 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004651 }
4652
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004653 /* apply refines */
4654 for (i = 0; i < uses->refine_size; i++) {
4655 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004656 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4657 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004658 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004659 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004660 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004661 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004662 }
4663
Radek Krejci1d82ef62015-08-07 14:44:40 +02004664 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004665 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004666 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004667 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004668 }
Pavol Vican855ca622016-09-05 13:07:54 +02004669 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004670
4671 /* description on any nodetype */
4672 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004673 lydict_remove(ctx, node->dsc);
4674 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004675 }
4676
4677 /* reference on any nodetype */
4678 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004679 lydict_remove(ctx, node->ref);
4680 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004681 }
4682
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004683 /* config on any nodetype,
4684 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4685 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004686 node->flags &= ~LYS_CONFIG_MASK;
4687 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004688 }
4689
4690 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004691 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004692 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004693 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004694 leaf = (struct lys_node_leaf *)node;
4695
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004696 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004697 lydict_remove(ctx, leaf->dflt);
4698 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4699
4700 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004701 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4702 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004703 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004704 }
Radek Krejci200bf712016-08-16 17:11:04 +02004705 } else if (node->nodetype == LYS_LEAFLIST) {
4706 /* leaf-list */
4707 llist = (struct lys_node_leaflist *)node;
4708
4709 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004710 for (j = 0; j < llist->dflt_size; j++) {
4711 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004712 }
4713 free(llist->dflt);
4714
4715 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02004716 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
4717 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM, fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004718 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004719 for (j = 0; j < llist->dflt_size; j++) {
4720 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004721 }
4722
4723 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004724 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004725 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004726 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004727 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004728 }
4729 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004730 }
4731 }
4732
4733 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004734 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004735 /* remove current value */
4736 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004737
Radek Krejcibf285832017-01-26 16:05:41 +01004738 /* set new value */
4739 node->flags |= (rfn->flags & LYS_MAND_MASK);
4740
Pavol Vican855ca622016-09-05 13:07:54 +02004741 if (rfn->flags & LYS_MAND_TRUE) {
4742 /* check if node has default value */
4743 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004744 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4745 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004746 goto fail;
4747 }
4748 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004749 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4750 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004751 goto fail;
4752 }
4753 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004754 }
4755
4756 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004757 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4758 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4759 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004760 }
4761
4762 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004763 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004764 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004765 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004766 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004767 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004768 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004769 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004770 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004771 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004772 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004773 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004774 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004775 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004776 }
4777 }
4778
4779 /* must in leaf, leaf-list, list, container or anyxml */
4780 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004781 switch (node->nodetype) {
4782 case LYS_LEAF:
4783 old_size = &((struct lys_node_leaf *)node)->must_size;
4784 old_must = &((struct lys_node_leaf *)node)->must;
4785 break;
4786 case LYS_LEAFLIST:
4787 old_size = &((struct lys_node_leaflist *)node)->must_size;
4788 old_must = &((struct lys_node_leaflist *)node)->must;
4789 break;
4790 case LYS_LIST:
4791 old_size = &((struct lys_node_list *)node)->must_size;
4792 old_must = &((struct lys_node_list *)node)->must;
4793 break;
4794 case LYS_CONTAINER:
4795 old_size = &((struct lys_node_container *)node)->must_size;
4796 old_must = &((struct lys_node_container *)node)->must;
4797 break;
4798 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004799 case LYS_ANYDATA:
4800 old_size = &((struct lys_node_anydata *)node)->must_size;
4801 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004802 break;
4803 default:
4804 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004805 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004806 }
4807
4808 size = *old_size + rfn->must_size;
4809 must = realloc(*old_must, size * sizeof *rfn->must);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004810 LY_CHECK_ERR_GOTO(!must, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004811 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004812 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004813 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 +02004814 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004815 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4816 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4817 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4818 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4819 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02004820 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004821 }
4822
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004823 *old_must = must;
4824 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004825
4826 /* check XPath dependencies again */
4827 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4828 goto fail;
4829 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004830 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004831
4832 /* if-feature in leaf, leaf-list, list, container or anyxml */
4833 if (rfn->iffeature_size) {
4834 old_size = &node->iffeature_size;
4835 old_iff = &node->iffeature;
4836
4837 size = *old_size + rfn->iffeature_size;
4838 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004839 LY_CHECK_ERR_GOTO(!iff, LOGMEM, fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02004840 *old_iff = iff;
4841
Pavol Vican855ca622016-09-05 13:07:54 +02004842 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4843 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004844 if (usize1) {
4845 /* there is something to duplicate */
4846 /* duplicate compiled expression */
4847 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4848 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004849 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004850 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004851
4852 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004853 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Radek Krejciaa1303c2017-05-31 13:57:37 +02004854 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004855 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004856
Radek Krejci3a3b2002017-09-13 16:39:02 +02004857 /* duplicate extensions */
4858 iff[j].ext_size = rfn->iffeature[k].ext_size;
4859 lys_ext_dup(rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
4860 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
4861 }
4862 (*old_size)++;
4863 }
4864 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004865 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004866 }
4867
4868 /* apply augments */
4869 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004870 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004871 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004872 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004873 }
4874 }
4875
Pavol Vican855ca622016-09-05 13:07:54 +02004876 /* check refines */
4877 for (i = 0; i < uses->refine_size; i++) {
4878 node = refine_nodes[i];
4879 rfn = &uses->refine[i];
4880
4881 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004882 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004883 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004884 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004885 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4886 (rfn->flags & LYS_CONFIG_W)) {
4887 /* setting config true under config false is prohibited */
4888 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004889 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004890 "changing config from 'false' to 'true' is prohibited while "
4891 "the target's parent is still config 'false'.");
4892 goto fail;
4893 }
4894
4895 /* inherit config change to the target children */
4896 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4897 if (rfn->flags & LYS_CONFIG_W) {
4898 if (iter->flags & LYS_CONFIG_SET) {
4899 /* config is set explicitely, go to next sibling */
4900 next = NULL;
4901 goto nextsibling;
4902 }
4903 } else { /* LYS_CONFIG_R */
4904 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4905 /* error - we would have config data under status data */
4906 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004907 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004908 "changing config from 'true' to 'false' is prohibited while the target "
4909 "has still a children with explicit config 'true'.");
4910 goto fail;
4911 }
4912 }
4913 /* change config */
4914 iter->flags &= ~LYS_CONFIG_MASK;
4915 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4916
4917 /* select next iter - modified LY_TREE_DFS_END */
4918 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4919 next = NULL;
4920 } else {
4921 next = iter->child;
4922 }
4923nextsibling:
4924 if (!next) {
4925 /* try siblings */
4926 next = iter->next;
4927 }
4928 while (!next) {
4929 /* parent is already processed, go to its sibling */
4930 iter = lys_parent(iter);
4931
4932 /* no siblings, go back through parents */
4933 if (iter == node) {
4934 /* we are done, no next element to process */
4935 break;
4936 }
4937 next = iter->next;
4938 }
4939 }
4940 }
4941
4942 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004943 if (rfn->dflt_size) {
4944 if (node->nodetype == LYS_CHOICE) {
4945 /* choice */
4946 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4947 rfn->dflt[0]);
4948 if (!((struct lys_node_choice *)node)->dflt) {
4949 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4950 goto fail;
4951 }
4952 if (lyp_check_mandatory_choice(node)) {
4953 goto fail;
4954 }
Pavol Vican855ca622016-09-05 13:07:54 +02004955 }
4956 }
4957
4958 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02004959 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004960 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004961 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4962 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004963 goto fail;
4964 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02004965 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004966 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004967 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4968 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004969 goto fail;
4970 }
4971 }
4972
4973 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004974 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004975 if (node->nodetype == LYS_LEAFLIST) {
4976 llist = (struct lys_node_leaflist *)node;
4977 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004978 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
4979 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004980 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4981 goto fail;
4982 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004983 } else if (node->nodetype == LYS_LEAF) {
4984 leaf = (struct lys_node_leaf *)node;
4985 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004986 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
4987 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004988 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4989 goto fail;
4990 }
Pavol Vican855ca622016-09-05 13:07:54 +02004991 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004992
Pavol Vican855ca622016-09-05 13:07:54 +02004993 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004994 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004995 for (parent = node->parent;
4996 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4997 parent = parent->parent) {
4998 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4999 /* stop also on presence containers */
5000 break;
5001 }
5002 }
5003 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5004 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5005 if (lyp_check_mandatory_choice(parent)) {
5006 goto fail;
5007 }
5008 }
5009 }
5010 }
5011 free(refine_nodes);
5012
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005013 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005014
5015fail:
5016 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5017 lys_node_free(iter, NULL, 0);
5018 }
Pavol Vican855ca622016-09-05 13:07:54 +02005019 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005020 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005021}
5022
Radek Krejci83a4bac2017-02-07 15:53:04 +01005023void
5024resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005025{
5026 int i;
5027
5028 assert(der && base);
5029
Radek Krejci018f1f52016-08-03 16:01:20 +02005030 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005031 /* create a set for backlinks if it does not exist */
5032 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005033 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005034 /* store backlink */
5035 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005036
Radek Krejci85a54be2016-10-20 12:39:56 +02005037 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005038 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005039 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005040 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005041}
5042
Michal Vasko730dfdf2015-08-11 14:48:05 +02005043/**
5044 * @brief Resolve base identity recursively. Does not log.
5045 *
5046 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005047 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005048 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005049 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005050 *
Radek Krejci219fa612016-08-15 10:36:51 +02005051 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005052 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005053static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005054resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005055 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005056{
Michal Vaskof02e3742015-08-05 16:27:02 +02005057 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005058 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005059
Radek Krejcicf509982015-12-15 09:22:44 +01005060 assert(ret);
5061
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005062 /* search module */
5063 for (i = 0; i < module->ident_size; i++) {
5064 if (!strcmp(basename, module->ident[i].name)) {
5065
5066 if (!ident) {
5067 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005068 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005069 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005070 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005071 }
5072
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005073 base = &module->ident[i];
5074 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005075 }
5076 }
5077
5078 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005079 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5080 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5081 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005082
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005083 if (!ident) {
5084 *ret = &module->inc[j].submodule->ident[i];
5085 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005086 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005087
5088 base = &module->inc[j].submodule->ident[i];
5089 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005090 }
5091 }
5092 }
5093
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005094matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005095 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005096 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005097 /* is it already completely resolved? */
5098 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005099 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005100 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5101
5102 /* simple check for circular reference,
5103 * the complete check is done as a side effect of using only completely
5104 * resolved identities (previous check of unres content) */
5105 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5106 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5107 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005108 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005109 }
5110
Radek Krejci06f64ed2016-08-15 11:07:44 +02005111 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005112 }
5113 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005114
Radek Krejcibabbff82016-02-19 13:31:37 +01005115 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005116 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005117 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005118 }
5119
Radek Krejci219fa612016-08-15 10:36:51 +02005120 /* base not found (maybe a forward reference) */
5121 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005122}
5123
Michal Vasko730dfdf2015-08-11 14:48:05 +02005124/**
5125 * @brief Resolve base identity. Logs directly.
5126 *
5127 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005128 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005129 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005130 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005131 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005132 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005133 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005134 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005135static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005136resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005137 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005138{
5139 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005140 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005141 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005142 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005143 struct lys_module *mod;
5144
5145 assert((ident && !type) || (!ident && type));
5146
5147 if (!type) {
5148 /* have ident to resolve */
5149 ret = &target;
5150 flags = ident->flags;
5151 mod = ident->module;
5152 } else {
5153 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005154 ++type->info.ident.count;
5155 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 +02005156 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM, -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005157
5158 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005159 flags = type->parent->flags;
5160 mod = type->parent->module;
5161 }
Michal Vaskof2006002016-04-21 16:28:15 +02005162 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005163
5164 /* search for the base identity */
5165 name = strchr(basename, ':');
5166 if (name) {
5167 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005168 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005169 name++;
5170
Michal Vasko2d851a92015-10-20 16:16:36 +02005171 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005172 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005173 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174 }
5175 } else {
5176 name = basename;
5177 }
5178
Radek Krejcic071c542016-01-27 14:57:51 +01005179 /* get module where to search */
5180 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5181 if (!module) {
5182 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005183 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005184 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005185 }
5186
Radek Krejcic071c542016-01-27 14:57:51 +01005187 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005188 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5189 if (!rc) {
5190 assert(*ret);
5191
5192 /* check status */
5193 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5194 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5195 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005196 } else if (ident) {
5197 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005198 if (lys_main_module(mod)->implemented) {
5199 /* in case of the implemented identity, maintain backlinks to it
5200 * from the base identities to make it available when resolving
5201 * data with the identity values (not implemented identity is not
5202 * allowed as an identityref value). */
5203 resolve_identity_backlink_update(ident, *ret);
5204 }
Radek Krejci219fa612016-08-15 10:36:51 +02005205 }
5206 } else if (rc == EXIT_FAILURE) {
5207 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005208 if (type) {
5209 --type->info.ident.count;
5210 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005211 }
5212
Radek Krejci219fa612016-08-15 10:36:51 +02005213 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005214}
5215
Radek Krejci9e6af732017-04-27 14:40:25 +02005216/*
5217 * 1 - true (der is derived from base)
5218 * 0 - false (der is not derived from base)
5219 */
5220static int
5221search_base_identity(struct lys_ident *der, struct lys_ident *base)
5222{
5223 int i;
5224
5225 if (der == base) {
5226 return 1;
5227 } else {
5228 for(i = 0; i < der->base_size; i++) {
5229 if (search_base_identity(der->base[i], base) == 1) {
5230 return 1;
5231 }
5232 }
5233 }
5234
5235 return 0;
5236}
5237
Michal Vasko730dfdf2015-08-11 14:48:05 +02005238/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005239 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005240 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005241 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005242 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005243 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005244 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005245 *
5246 * @return Pointer to the identity resolvent, NULL on error.
5247 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005248struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005249resolve_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 +02005250{
Radek Krejci9e6af732017-04-27 14:40:25 +02005251 const char *mod_name, *name;
Radek Krejcidce5f972017-09-12 15:47:49 +02005252 int mod_name_len, nam_len, rc;
Radek Krejci9e6af732017-04-27 14:40:25 +02005253 int make_implemented = 0;
Radek Krejcidce5f972017-09-12 15:47:49 +02005254 unsigned int u, i, j;
Michal Vaskof2d43962016-09-02 11:10:16 +02005255 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005256 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005257
Radek Krejci9e6af732017-04-27 14:40:25 +02005258 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005259
Michal Vaskof2d43962016-09-02 11:10:16 +02005260 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005261 return NULL;
5262 }
5263
Michal Vasko50576712017-07-28 12:28:33 +02005264 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005265 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005266 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005267 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005268 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005269 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005270 return NULL;
5271 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005272
5273 m = lys_main_module(mod); /* shortcut */
5274 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5275 /* identity is defined in the same module as node */
5276 imod = m;
5277 } else if (dflt) {
5278 /* solving identityref in default definition in schema -
5279 * find the identity's module in the imported modules list to have a correct revision */
5280 for (i = 0; i < mod->imp_size; i++) {
5281 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5282 imod = mod->imp[i].module;
5283 break;
5284 }
5285 }
5286 } else {
5287 /* solving identityref in data - get the (implemented) module from the context */
5288 u = 0;
5289 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5290 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5291 break;
5292 }
5293 }
5294 }
5295 if (!imod) {
5296 goto fail;
5297 }
5298
5299 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5300 /* we are solving default statement in schema AND the type is not referencing the same schema,
5301 * THEN, we may need to make the module with the identity implemented, but only if it really
5302 * contains the identity */
5303 if (!imod->implemented) {
5304 cur = NULL;
5305 /* get the identity in the module */
5306 for (i = 0; i < imod->ident_size; i++) {
5307 if (!strcmp(name, imod->ident[i].name)) {
5308 cur = &imod->ident[i];
5309 break;
5310 }
5311 }
5312 if (!cur) {
5313 /* go through includes */
5314 for (j = 0; j < imod->inc_size; j++) {
5315 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5316 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5317 cur = &imod->inc[j].submodule->ident[i];
5318 break;
5319 }
5320 }
5321 }
5322 if (!cur) {
5323 goto fail;
5324 }
5325 }
5326
5327 /* check that identity is derived from one of the type's base */
5328 while (type->der) {
5329 for (i = 0; i < type->info.ident.count; i++) {
5330 if (search_base_identity(cur, type->info.ident.ref[i])) {
5331 /* cur's base matches the type's base */
5332 make_implemented = 1;
5333 goto match;
5334 }
5335 }
5336 type = &type->der->type;
5337 }
5338 /* matching base not found */
5339 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5340 goto fail;
5341 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005342 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005343
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005344 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005345 while (type->der) {
5346 for (i = 0; i < type->info.ident.count; ++i) {
5347 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005348
Radek Krejci85a54be2016-10-20 12:39:56 +02005349 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005350 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005351 for (u = 0; u < cur->der->number; u++) {
5352 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005353 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005354 /* we have match */
5355 cur = der;
5356 goto match;
5357 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005358 }
5359 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005360 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005361 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005362 }
5363
Radek Krejci9e6af732017-04-27 14:40:25 +02005364fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005365 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005366 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005367
5368match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005369 for (i = 0; i < cur->iffeature_size; i++) {
5370 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005371 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005372 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 +02005373 return NULL;
5374 }
5375 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005376 if (make_implemented) {
5377 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5378 imod->name, cur->name, mod->name);
5379 if (lys_set_implemented(imod)) {
5380 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5381 imod->name, cur->name);
5382 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5383 goto fail;
5384 }
5385 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005386 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005387}
5388
Michal Vasko730dfdf2015-08-11 14:48:05 +02005389/**
Michal Vaskobb211122015-08-19 14:03:11 +02005390 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005391 *
Michal Vaskobb211122015-08-19 14:03:11 +02005392 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005393 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005394 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005395 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005396 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005397static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005398resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005399{
Radek Krejci93def382017-05-24 15:33:48 +02005400 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005401 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005402
Radek Krejci6ff885d2017-01-03 14:06:22 +01005403 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
Radek Krejci93def382017-05-24 15:33:48 +02005404 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5405 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5406 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005407 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 +02005408
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005409 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005410 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5411 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005412 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005413 return -1;
5414 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005415 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005416 return -1;
5417 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005418 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005419 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5420 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5421 return -1;
5422 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005423 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005424 }
Michal Vasko92981a62016-10-14 10:25:16 +02005425 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005426 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005427 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005428 }
5429
Radek Krejci93def382017-05-24 15:33:48 +02005430 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005431 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005432 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5433 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5434 return -1;
5435 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005436 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005437 } else {
5438 /* instantiate grouping only when it is completely resolved */
5439 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005440 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005441 return EXIT_FAILURE;
5442 }
5443
Radek Krejci48464ed2016-03-17 15:44:09 +01005444 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005445 if (!rc) {
5446 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005447 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005448 assert(((struct lys_node_grp *)par_grp)->unres_count);
5449 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005450 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005451 }
Radek Krejcicf509982015-12-15 09:22:44 +01005452
5453 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005454 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005455 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005456 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005457 return -1;
5458 }
5459
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005460 return EXIT_SUCCESS;
5461 }
5462
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005463 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005464}
5465
Michal Vasko730dfdf2015-08-11 14:48:05 +02005466/**
Michal Vasko9957e592015-08-17 15:04:09 +02005467 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005468 *
Michal Vaskobb211122015-08-19 14:03:11 +02005469 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005470 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005471 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005472 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005473 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005474static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005475resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005476{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005477 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005478 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005479 char *s = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005480
5481 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005482 assert(keys_str);
5483
Radek Krejci5c08a992016-11-02 13:30:04 +01005484 if (!list->child) {
5485 /* no child, possible forward reference */
5486 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5487 return EXIT_FAILURE;
5488 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005489 /* get the key name */
5490 if ((value = strpbrk(keys_str, " \t\n"))) {
5491 len = value - keys_str;
5492 while (isspace(value[0])) {
5493 value++;
5494 }
5495 } else {
5496 len = strlen(keys_str);
5497 }
5498
Radek Krejcia98048c2017-05-24 16:35:48 +02005499 if (list->keys[i]) {
5500 /* skip already resolved keys */
5501 goto next;
5502 }
5503
Michal Vaskobb520442017-05-23 10:55:18 +02005504 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5505 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005506 if (rc) {
Radek Krejcia98048c2017-05-24 16:35:48 +02005507 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005508 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005509 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005510
Radek Krejci48464ed2016-03-17 15:44:09 +01005511 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005512 /* check_key logs */
5513 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005514 }
5515
Radek Krejcicf509982015-12-15 09:22:44 +01005516 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005517 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005518 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5519 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005520 return -1;
5521 }
5522
Radek Krejcia98048c2017-05-24 16:35:48 +02005523 /* default value - is ignored, keep it but print a warning */
5524 if (list->keys[i]->dflt) {
5525 /* log is not hidden only in case this resolving fails and in such a case
5526 * we cannot get here
5527 */
Michal Vasko4814fb02017-08-17 14:49:38 +02005528 assert(ly_err_main.vlog_hide);
Radek Krejcia98048c2017-05-24 16:35:48 +02005529 ly_vlog_hide(0);
5530 LOGWRN("Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
5531 list->keys[i]->name, s = lys_path((struct lys_node*)list));
5532 ly_vlog_hide(1);
5533 free(s);
5534 }
5535
5536next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005537 /* prepare for next iteration */
5538 while (value && isspace(value[0])) {
5539 value++;
5540 }
5541 keys_str = value;
5542 }
5543
Michal Vaskof02e3742015-08-05 16:27:02 +02005544 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005545}
5546
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005547/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005548 * @brief Resolve (check) all must conditions of \p node.
5549 * Logs directly.
5550 *
5551 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005552 * @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 +02005553 *
5554 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5555 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005556static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005557resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005558{
Michal Vaskobf19d252015-10-08 15:39:17 +02005559 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005560 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005561 struct lys_restr *must;
5562 struct lyxp_set set;
5563
5564 assert(node);
5565 memset(&set, 0, sizeof set);
5566
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005567 if (inout_parent) {
5568 for (schema = lys_parent(node->schema);
5569 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5570 schema = lys_parent(schema));
5571 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5572 LOGINT;
5573 return -1;
5574 }
5575 must_size = ((struct lys_node_inout *)schema)->must_size;
5576 must = ((struct lys_node_inout *)schema)->must;
5577
5578 /* context node is the RPC/action */
5579 node = node->parent;
5580 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5581 LOGINT;
5582 return -1;
5583 }
5584 } else {
5585 switch (node->schema->nodetype) {
5586 case LYS_CONTAINER:
5587 must_size = ((struct lys_node_container *)node->schema)->must_size;
5588 must = ((struct lys_node_container *)node->schema)->must;
5589 break;
5590 case LYS_LEAF:
5591 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5592 must = ((struct lys_node_leaf *)node->schema)->must;
5593 break;
5594 case LYS_LEAFLIST:
5595 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5596 must = ((struct lys_node_leaflist *)node->schema)->must;
5597 break;
5598 case LYS_LIST:
5599 must_size = ((struct lys_node_list *)node->schema)->must_size;
5600 must = ((struct lys_node_list *)node->schema)->must;
5601 break;
5602 case LYS_ANYXML:
5603 case LYS_ANYDATA:
5604 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5605 must = ((struct lys_node_anydata *)node->schema)->must;
5606 break;
5607 case LYS_NOTIF:
5608 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5609 must = ((struct lys_node_notif *)node->schema)->must;
5610 break;
5611 default:
5612 must_size = 0;
5613 break;
5614 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005615 }
5616
5617 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005618 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005619 return -1;
5620 }
5621
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005622 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005623
Michal Vasko8146d4c2016-05-09 15:50:29 +02005624 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02005625 if ((ignore_fail == 1) || ((must[i].flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005626 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5627 } else {
5628 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5629 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005630 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005631 }
5632 if (must[i].eapptag) {
5633 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5634 }
5635 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005636 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005637 }
5638 }
5639
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005640 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005641}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005642
Michal Vaskobf19d252015-10-08 15:39:17 +02005643/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005644 * @brief Resolve (find) when condition schema context node. Does not log.
5645 *
5646 * @param[in] schema Schema node with the when condition.
5647 * @param[out] ctx_snode When schema context node.
5648 * @param[out] ctx_snode_type Schema context node type.
5649 */
5650void
5651resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5652{
5653 const struct lys_node *sparent;
5654
5655 /* find a not schema-only node */
5656 *ctx_snode_type = LYXP_NODE_ELEM;
5657 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5658 if (schema->nodetype == LYS_AUGMENT) {
5659 sparent = ((struct lys_node_augment *)schema)->target;
5660 } else {
5661 sparent = schema->parent;
5662 }
5663 if (!sparent) {
5664 /* context node is the document root (fake root in our case) */
5665 if (schema->flags & LYS_CONFIG_W) {
5666 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5667 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005668 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005669 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005670 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005671 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005672 break;
5673 }
5674 schema = sparent;
5675 }
5676
5677 *ctx_snode = (struct lys_node *)schema;
5678}
5679
5680/**
Michal Vaskocf024702015-10-08 15:01:42 +02005681 * @brief Resolve (find) when condition context node. Does not log.
5682 *
5683 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005684 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005685 * @param[out] ctx_node Context node.
5686 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005687 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005688 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005689 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005690static int
5691resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5692 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005693{
Michal Vaskocf024702015-10-08 15:01:42 +02005694 struct lyd_node *parent;
5695 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005696 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005697 uint16_t i, data_depth, schema_depth;
5698
Michal Vasko508a50d2016-09-07 14:50:33 +02005699 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005700
Michal Vaskofe989752016-09-08 08:47:26 +02005701 if (node_type == LYXP_NODE_ELEM) {
5702 /* standard element context node */
5703 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5704 for (sparent = schema, schema_depth = 0;
5705 sparent;
5706 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5707 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5708 ++schema_depth;
5709 }
Michal Vaskocf024702015-10-08 15:01:42 +02005710 }
Michal Vaskofe989752016-09-08 08:47:26 +02005711 if (data_depth < schema_depth) {
5712 return -1;
5713 }
Michal Vaskocf024702015-10-08 15:01:42 +02005714
Michal Vasko956e8542016-08-26 09:43:35 +02005715 /* find the corresponding data node */
5716 for (i = 0; i < data_depth - schema_depth; ++i) {
5717 node = node->parent;
5718 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005719 if (node->schema != schema) {
5720 return -1;
5721 }
Michal Vaskofe989752016-09-08 08:47:26 +02005722 } else {
5723 /* root context node */
5724 while (node->parent) {
5725 node = node->parent;
5726 }
5727 while (node->prev->next) {
5728 node = node->prev;
5729 }
Michal Vaskocf024702015-10-08 15:01:42 +02005730 }
5731
Michal Vaskoa59495d2016-08-22 09:18:58 +02005732 *ctx_node = node;
5733 *ctx_node_type = node_type;
5734 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005735}
5736
Michal Vasko76c3bd32016-08-24 16:02:52 +02005737/**
5738 * @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 +01005739 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005740 *
5741 * @param[in] snode Schema node, whose children instances need to be unlinked.
5742 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5743 * it is moved to point to another sibling still in the original tree.
5744 * @param[in,out] ctx_node When context node, adjusted if needed.
5745 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5746 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5747 * Ordering may change, but there will be no semantic change.
5748 *
5749 * @return EXIT_SUCCESS on success, -1 on error.
5750 */
5751static int
5752resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5753 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5754{
5755 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005756 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005757
5758 switch (snode->nodetype) {
5759 case LYS_AUGMENT:
5760 case LYS_USES:
5761 case LYS_CHOICE:
5762 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005763 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005764 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005765 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5766 continue;
5767 }
5768
5769 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005770 return -1;
5771 }
5772 }
5773 break;
5774 case LYS_CONTAINER:
5775 case LYS_LIST:
5776 case LYS_LEAF:
5777 case LYS_LEAFLIST:
5778 case LYS_ANYXML:
5779 case LYS_ANYDATA:
5780 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5781 if (elem->schema == snode) {
5782
5783 if (elem == *ctx_node) {
5784 /* We are going to unlink our context node! This normally cannot happen,
5785 * but we use normal top-level data nodes for faking a document root node,
5786 * so if this is the context node, we just use the next top-level node.
5787 * Additionally, it can even happen that there are no top-level data nodes left,
5788 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5789 * lyxp_eval() can handle this special situation.
5790 */
5791 if (ctx_node_type == LYXP_NODE_ELEM) {
5792 LOGINT;
5793 return -1;
5794 }
5795
5796 if (elem->prev == elem) {
5797 /* unlinking last top-level element, use an empty data tree */
5798 *ctx_node = NULL;
5799 } else {
5800 /* in this case just use the previous/last top-level data node */
5801 *ctx_node = elem->prev;
5802 }
5803 } else if (elem == *node) {
5804 /* We are going to unlink the currently processed node. This does not matter that
5805 * much, but we would lose access to the original data tree, so just move our
5806 * pointer somewhere still inside it.
5807 */
5808 if ((*node)->prev != *node) {
5809 *node = (*node)->prev;
5810 } else {
5811 /* the processed node with sibings were all unlinked, oh well */
5812 *node = NULL;
5813 }
5814 }
5815
5816 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005817 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005818 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005819 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005820 LOGINT;
5821 return -1;
5822 }
5823 } else {
5824 *unlinked_nodes = elem;
5825 }
5826
5827 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5828 /* there can be only one instance */
5829 break;
5830 }
5831 }
5832 }
5833 break;
5834 default:
5835 LOGINT;
5836 return -1;
5837 }
5838
5839 return EXIT_SUCCESS;
5840}
5841
5842/**
5843 * @brief Relink the unlinked nodes back.
5844 *
5845 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5846 * we simply need a sibling from the original data tree.
5847 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5848 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5849 * or the sibling of \p unlinked_nodes.
5850 *
5851 * @return EXIT_SUCCESS on success, -1 on error.
5852 */
5853static int
5854resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5855{
5856 struct lyd_node *elem;
5857
5858 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005859 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005860 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005861 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005862 return -1;
5863 }
5864 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005865 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005866 return -1;
5867 }
5868 }
5869 }
5870
5871 return EXIT_SUCCESS;
5872}
5873
Radek Krejci03b71f72016-03-16 11:10:09 +01005874int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005875resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005876{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005877 int ret = 0;
5878 uint8_t must_size;
5879 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005880
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005881 assert(node);
5882
5883 schema = node->schema;
5884
5885 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005886 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005887 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005888 must_size = ((struct lys_node_container *)schema)->must_size;
5889 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005890 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005891 must_size = ((struct lys_node_leaf *)schema)->must_size;
5892 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005893 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005894 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5895 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005896 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005897 must_size = ((struct lys_node_list *)schema)->must_size;
5898 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005899 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005900 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005901 must_size = ((struct lys_node_anydata *)schema)->must_size;
5902 break;
5903 case LYS_NOTIF:
5904 must_size = ((struct lys_node_notif *)schema)->must_size;
5905 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005906 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005907 must_size = 0;
5908 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005909 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005910
5911 if (must_size) {
5912 ++ret;
5913 }
5914
5915 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5916 if (!node->prev->next) {
5917 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5918 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5919 ret += 0x2;
5920 }
5921 }
5922
5923 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005924}
5925
5926int
Radek Krejci46165822016-08-26 14:06:27 +02005927resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005928{
Radek Krejci46165822016-08-26 14:06:27 +02005929 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005930
Radek Krejci46165822016-08-26 14:06:27 +02005931 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005932
Radek Krejci46165822016-08-26 14:06:27 +02005933 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005934 return 1;
5935 }
5936
Radek Krejci46165822016-08-26 14:06:27 +02005937 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005938 goto check_augment;
5939
Radek Krejci46165822016-08-26 14:06:27 +02005940 while (parent) {
5941 /* stop conditions */
5942 if (!mode) {
5943 /* stop on node that can be instantiated in data tree */
5944 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5945 break;
5946 }
5947 } else {
5948 /* stop on the specified node */
5949 if (parent == stop) {
5950 break;
5951 }
5952 }
5953
5954 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005955 return 1;
5956 }
5957check_augment:
5958
5959 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005960 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005961 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005962 }
5963 parent = lys_parent(parent);
5964 }
5965
5966 return 0;
5967}
5968
Michal Vaskocf024702015-10-08 15:01:42 +02005969/**
5970 * @brief Resolve (check) all when conditions relevant for \p node.
5971 * Logs directly.
5972 *
5973 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02005974 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
5975 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02005976 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005977 * @return
5978 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02005979 * 0 - all "when" statements true
5980 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01005981 * 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 +02005982 */
Radek Krejci46165822016-08-26 14:06:27 +02005983int
Michal Vasko0b963112017-08-11 12:45:36 +02005984resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02005985{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005986 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005987 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005988 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005989 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005990 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005991
5992 assert(node);
5993 memset(&set, 0, sizeof set);
5994
Michal Vasko78d97e22017-02-21 09:54:38 +01005995 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005996 /* make the node dummy for the evaluation */
5997 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005998 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5999 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006000 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006001 if (rc) {
6002 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006003 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006004 }
Radek Krejci51093642016-03-29 10:14:59 +02006005 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006006 }
6007
Radek Krejci03b71f72016-03-16 11:10:09 +01006008 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006009 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006010 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006011 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006012 if ((ignore_fail == 1)
6013 || ((((struct lys_node_container *)node->schema)->when->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006014 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6015 ((struct lys_node_container *)node->schema)->when->cond);
6016 } else {
6017 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006018 if (failed_when) {
6019 *failed_when = ((struct lys_node_container *)node->schema)->when;
6020 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006021 goto cleanup;
6022 }
Michal Vaskocf024702015-10-08 15:01:42 +02006023 }
Radek Krejci51093642016-03-29 10:14:59 +02006024
6025 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006026 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006027 }
6028
Michal Vasko90fc2a32016-08-24 15:58:58 +02006029 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006030 goto check_augment;
6031
6032 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006033 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6034 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006035 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006036 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006037 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006038 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006039 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006040 }
6041 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006042
6043 unlinked_nodes = NULL;
6044 /* we do not want our node pointer to change */
6045 tmp_node = node;
6046 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6047 if (rc) {
6048 goto cleanup;
6049 }
6050
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006051 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6052 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006053
6054 if (unlinked_nodes && ctx_node) {
6055 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6056 rc = -1;
6057 goto cleanup;
6058 }
6059 }
6060
Radek Krejci03b71f72016-03-16 11:10:09 +01006061 if (rc) {
6062 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006063 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006064 }
Radek Krejci51093642016-03-29 10:14:59 +02006065 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006066 }
6067
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006068 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006069 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02006070 if ((ignore_fail == 1)
6071 || ((((struct lys_node_uses *)sparent)->when->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006072 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6073 ((struct lys_node_uses *)sparent)->when->cond);
6074 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006075 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006076 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006077 if (failed_when) {
6078 *failed_when = ((struct lys_node_uses *)sparent)->when;
6079 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006080 goto cleanup;
6081 }
Michal Vaskocf024702015-10-08 15:01:42 +02006082 }
Radek Krejci51093642016-03-29 10:14:59 +02006083
6084 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006085 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006086 }
6087
6088check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006089 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006090 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006091 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006092 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006093 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006094 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006095 }
6096 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006097
6098 unlinked_nodes = NULL;
6099 tmp_node = node;
6100 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6101 if (rc) {
6102 goto cleanup;
6103 }
6104
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006105 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6106 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006107
6108 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6109 * so the tree did not actually change and there is nothing for us to do
6110 */
6111 if (unlinked_nodes && ctx_node) {
6112 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6113 rc = -1;
6114 goto cleanup;
6115 }
6116 }
6117
Radek Krejci03b71f72016-03-16 11:10:09 +01006118 if (rc) {
6119 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006120 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006121 }
Radek Krejci51093642016-03-29 10:14:59 +02006122 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006123 }
6124
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006125 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006126 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006127 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006128 if ((ignore_fail == 1)
6129 || ((((struct lys_node_augment *)sparent->parent)->when->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006130 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006131 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006132 } else {
6133 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006134 if (failed_when) {
6135 *failed_when = ((struct lys_node_augment *)sparent->parent)->when;
6136 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006137 goto cleanup;
6138 }
Michal Vaskocf024702015-10-08 15:01:42 +02006139 }
Radek Krejci51093642016-03-29 10:14:59 +02006140
6141 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006142 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006143 }
6144
Michal Vasko90fc2a32016-08-24 15:58:58 +02006145 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006146 }
6147
Radek Krejci0b7704f2016-03-18 12:16:14 +01006148 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006149
Radek Krejci51093642016-03-29 10:14:59 +02006150cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006151 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006152 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006153 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006154}
6155
Radek Krejcicbb473e2016-09-16 14:48:32 +02006156static int
6157check_leafref_features(struct lys_type *type)
6158{
6159 struct lys_node *iter;
6160 struct ly_set *src_parents, *trg_parents, *features;
6161 unsigned int i, j, size, x;
6162 int ret = EXIT_SUCCESS;
6163
6164 assert(type->parent);
6165
6166 src_parents = ly_set_new();
6167 trg_parents = ly_set_new();
6168 features = ly_set_new();
6169
6170 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006171 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006172 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6173 continue;
6174 }
6175 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6176 }
6177 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006178 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006179 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6180 continue;
6181 }
6182 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6183 }
6184
6185 /* compare the features used in if-feature statements in the rest of both
6186 * chains of parents. The set of features used for target must be a subset
6187 * of features used for the leafref. This is not a perfect, we should compare
6188 * the truth tables but it could require too much resources, so we simplify that */
6189 for (i = 0; i < src_parents->number; i++) {
6190 iter = src_parents->set.s[i]; /* shortcut */
6191 if (!iter->iffeature_size) {
6192 continue;
6193 }
6194 for (j = 0; j < iter->iffeature_size; j++) {
6195 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6196 for (; size; size--) {
6197 if (!iter->iffeature[j].features[size - 1]) {
6198 /* not yet resolved feature, postpone this check */
6199 ret = EXIT_FAILURE;
6200 goto cleanup;
6201 }
6202 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6203 }
6204 }
6205 }
6206 x = features->number;
6207 for (i = 0; i < trg_parents->number; i++) {
6208 iter = trg_parents->set.s[i]; /* shortcut */
6209 if (!iter->iffeature_size) {
6210 continue;
6211 }
6212 for (j = 0; j < iter->iffeature_size; j++) {
6213 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6214 for (; size; size--) {
6215 if (!iter->iffeature[j].features[size - 1]) {
6216 /* not yet resolved feature, postpone this check */
6217 ret = EXIT_FAILURE;
6218 goto cleanup;
6219 }
6220 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6221 /* the feature is not present in features set of target's parents chain */
6222 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006223 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006224 "Leafref is not conditional based on \"%s\" feature as its target.",
6225 iter->iffeature[j].features[size - 1]->name);
6226 ret = -1;
6227 goto cleanup;
6228 }
6229 }
6230 }
6231 }
6232
6233cleanup:
6234 ly_set_free(features);
6235 ly_set_free(src_parents);
6236 ly_set_free(trg_parents);
6237
6238 return ret;
6239}
6240
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006241static int
6242check_type_union_leafref(struct lys_type *type)
6243{
6244 uint8_t i;
6245
6246 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6247 /* go through unions and look for leafref */
6248 for (i = 0; i < type->info.uni.count; ++i) {
6249 switch (type->info.uni.types[i].base) {
6250 case LY_TYPE_LEAFREF:
6251 return 1;
6252 case LY_TYPE_UNION:
6253 if (check_type_union_leafref(&type->info.uni.types[i])) {
6254 return 1;
6255 }
6256 break;
6257 default:
6258 break;
6259 }
6260 }
6261
6262 return 0;
6263 }
6264
6265 /* just inherit the flag value */
6266 return type->der->has_union_leafref;
6267}
6268
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006269/**
Michal Vaskobb211122015-08-19 14:03:11 +02006270 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006271 *
6272 * @param[in] mod Main module.
6273 * @param[in] item Item to resolve. Type determined by \p type.
6274 * @param[in] type Type of the unresolved item.
6275 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006276 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006277 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006278 *
6279 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6280 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006281static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006282resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006283 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006284{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006285 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006286 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006287 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006288 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006289 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006290 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006291
Radek Krejcic79c6b12016-07-26 15:11:49 +02006292 struct ly_set *refs, *procs;
6293 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006294 struct lys_ident *ident;
6295 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006296 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006297 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006298 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006299 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006300 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006301 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006302 struct lys_ext_instance *ext, **extlist;
6303 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006304
6305 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006306 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006307 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006308 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006309 ident = item;
6310
Radek Krejci018f1f52016-08-03 16:01:20 +02006311 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006312 break;
6313 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006314 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006315 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006316 stype = item;
6317
Radek Krejci018f1f52016-08-03 16:01:20 +02006318 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006319 break;
6320 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006321 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006322 stype = item;
6323
Michal Vasko1c007172017-03-10 10:20:44 +01006324 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6325 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006326 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006327 /* check if leafref and its target are under a common if-features */
6328 rc = check_leafref_features(stype);
6329 if (rc) {
6330 break;
6331 }
6332
Michal Vaskobb520442017-05-23 10:55:18 +02006333 if (lys_node_module(node)->implemented) {
6334 /* make all the modules on the path implemented */
6335 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6336 if (!lys_node_module(next)->implemented) {
6337 if (lys_set_implemented(lys_node_module(next))) {
6338 rc = -1;
6339 break;
6340 }
6341 }
6342 }
6343 if (next) {
6344 break;
6345 }
6346
6347 /* store the backlink from leafref target */
6348 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6349 rc = -1;
6350 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006351 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006352 }
6353
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006354 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006355 case UNRES_TYPE_DER_EXT:
6356 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006357 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006358 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006359 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006360 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006361 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006362 /* parent */
6363 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006364 stype = item;
6365
Michal Vasko88c29542015-11-27 14:57:53 +01006366 /* HACK type->der is temporarily unparsed type statement */
6367 yin = (struct lyxml_elem *)stype->der;
6368 stype->der = NULL;
6369
Pavol Vicana0e4e672016-02-24 12:20:04 +01006370 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6371 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006372 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006373
6374 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006375 /* may try again later */
6376 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006377 } else {
6378 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006379 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006380 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006381 }
6382
Michal Vasko88c29542015-11-27 14:57:53 +01006383 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006384 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006385 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006386 /* we need to always be able to free this, it's safe only in this case */
6387 lyxml_free(mod->ctx, yin);
6388 } else {
6389 /* may try again later, put all back how it was */
6390 stype->der = (struct lys_tpdf *)yin;
6391 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006392 }
Radek Krejcic13db382016-08-16 10:52:42 +02006393 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006394 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006395 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006396 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6397 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006398
6399 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6400 /* fill typedef union leafref flag */
6401 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6402 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6403 /* copy the type in case it has union leafref flag */
6404 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
6405 LOGERR(LY_EINT, "Failed to duplicate type.");
6406 return -1;
6407 }
6408 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006409 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006410 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6411 * by uses statement until the type is resolved. We do that the same way as uses statements inside
Radek Krejci93def382017-05-24 15:33:48 +02006412 * grouping. The grouping cannot be used unless the unres counter is 0.
6413 * To remember that the grouping already increased the counter, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006414 * of the type's base member. */
6415 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6416 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006417 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6418 LOGERR(LY_EINT, "Too many unresolved items (type) inside a grouping.");
6419 return -1;
6420 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006421 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006422 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006423 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006424 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006425 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006426 iff_data = str_snode;
6427 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006428 if (!rc) {
6429 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006430 if (iff_data->infeature) {
6431 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6432 feat = *((struct lys_feature **)item);
6433 if (!feat->depfeatures) {
6434 feat->depfeatures = ly_set_new();
6435 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006436 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006437 }
6438 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006439 lydict_remove(mod->ctx, iff_data->fname);
6440 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006441 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006442 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006443 case UNRES_FEATURE:
6444 feat = (struct lys_feature *)item;
6445
6446 if (feat->iffeature_size) {
6447 refs = ly_set_new();
6448 procs = ly_set_new();
6449 ly_set_add(procs, feat, 0);
6450
6451 while (procs->number) {
6452 ref = procs->set.g[procs->number - 1];
6453 ly_set_rm_index(procs, procs->number - 1);
6454
6455 for (i = 0; i < ref->iffeature_size; i++) {
6456 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6457 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006458 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006459 if (ref->iffeature[i].features[j - 1] == feat) {
6460 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6461 goto featurecheckdone;
6462 }
6463
6464 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6465 k = refs->number;
6466 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6467 /* not yet seen feature, add it for processing */
6468 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6469 }
6470 }
6471 } else {
6472 /* forward reference */
6473 rc = EXIT_FAILURE;
6474 goto featurecheckdone;
6475 }
6476 }
6477
6478 }
6479 }
6480 rc = EXIT_SUCCESS;
6481
6482featurecheckdone:
6483 ly_set_free(refs);
6484 ly_set_free(procs);
6485 }
6486
6487 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006488 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006489 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006490 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006491 case UNRES_TYPEDEF_DFLT:
6492 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006493 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006494 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006495 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006496 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006497 break;
6498 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006499 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006500 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006501 choic = item;
6502
Radek Krejcie00d2312016-08-12 15:27:49 +02006503 if (!choic->dflt) {
6504 choic->dflt = resolve_choice_dflt(choic, expr);
6505 }
Michal Vasko7955b362015-09-04 14:18:15 +02006506 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006507 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006508 } else {
6509 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006510 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006511 break;
6512 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006513 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006514 break;
6515 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006516 unique_info = (struct unres_list_uniq *)item;
6517 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006518 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006519 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006520 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006521 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006522 case UNRES_XPATH:
6523 node = (struct lys_node *)item;
Michal Vaskof96dfb62017-08-17 12:23:49 +02006524 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006525 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006526 case UNRES_EXT:
6527 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006528 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006529 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006530 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006531 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006532 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006533 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006534 if (eplugin) {
6535 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006536 u = malloc(sizeof *u);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006537 LY_CHECK_ERR_RETURN(!u, LOGMEM, -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006538 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006539 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6540 /* something really bad happend since the extension finalization is not actually
6541 * being resolved while adding into unres, so something more serious with the unres
6542 * list itself must happened */
6543 return -1;
6544 }
Radek Krejci80056d52017-01-05 13:13:33 +01006545 }
6546 }
Radek Krejci79685c92017-02-17 10:49:43 +01006547 }
6548 if (!rc || rc == -1) {
6549 /* cleanup on success or fatal error */
6550 if (ext_data->datatype == LYS_IN_YIN) {
6551 /* YIN */
6552 lyxml_free(mod->ctx, ext_data->data.yin);
6553 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006554 /* YANG */
6555 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006556 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006557 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006558 }
6559 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006560 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006561 u = (uint8_t *)str_snode;
6562 ext = (*(struct lys_ext_instance ***)item)[*u];
6563 free(u);
6564
Radek Krejci80056d52017-01-05 13:13:33 +01006565 eplugin = ext->def->plugin;
6566
6567 /* inherit */
6568 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6569 root = (struct lys_node *)ext->parent;
6570 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6571 LY_TREE_DFS_BEGIN(root->child, next, node) {
6572 /* first, check if the node already contain instance of the same extension,
6573 * in such a case we won't inherit. In case the node was actually defined as
6574 * augment data, we are supposed to check the same way also the augment node itself */
6575 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6576 goto inherit_dfs_sibling;
6577 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6578 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6579 goto inherit_dfs_sibling;
6580 }
6581
6582 if (eplugin->check_inherit) {
6583 /* we have a callback to check the inheritance, use it */
6584 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6585 case 0:
6586 /* yes - continue with the inheriting code */
6587 break;
6588 case 1:
6589 /* no - continue with the node's sibling */
6590 goto inherit_dfs_sibling;
6591 case 2:
6592 /* no, but continue with the children, just skip the inheriting code for this node */
6593 goto inherit_dfs_child;
6594 default:
6595 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6596 ext->def->module->name, ext->def->name, rc);
6597 }
6598 }
6599
6600 /* inherit the extension */
6601 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006602 LY_CHECK_ERR_RETURN(!extlist, LOGMEM, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006603 extlist[node->ext_size] = malloc(sizeof **extlist);
Radek Krejciaa1303c2017-05-31 13:57:37 +02006604 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM; node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006605 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6606 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6607
6608 node->ext = extlist;
6609 node->ext_size++;
6610
6611inherit_dfs_child:
6612 /* modification of - select element for the next run - children first */
6613 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6614 next = NULL;
6615 } else {
6616 next = node->child;
6617 }
6618 if (!next) {
6619inherit_dfs_sibling:
6620 /* no children, try siblings */
6621 next = node->next;
6622 }
6623 while (!next) {
6624 /* go to the parent */
6625 node = lys_parent(node);
6626
6627 /* we are done if we are back in the root (the starter's parent */
6628 if (node == root) {
6629 break;
6630 }
6631
6632 /* parent is already processed, go to its sibling */
6633 next = node->next;
6634 }
6635 }
6636 }
6637 }
6638
6639 /* final check */
6640 if (eplugin->check_result) {
6641 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006642 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006643 return -1;
6644 }
6645 }
6646
6647 rc = 0;
6648 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006649 default:
6650 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006651 break;
6652 }
6653
Radek Krejci54081ce2016-08-12 15:21:47 +02006654 if (has_str && !rc) {
6655 /* the string is no more needed in case of success.
6656 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006657 lydict_remove(mod->ctx, str_snode);
6658 }
6659
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006660 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006661}
6662
Michal Vaskof02e3742015-08-05 16:27:02 +02006663/* logs directly */
6664static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006665print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006666{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006667 struct lyxml_elem *xml;
6668 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006669 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006670 const char *name = NULL;
6671 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006672
Michal Vaskof02e3742015-08-05 16:27:02 +02006673 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006674 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006675 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006676 break;
6677 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006678 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006679 break;
6680 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006681 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6682 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006683 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006684 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006685 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006686 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006687 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6688 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006689 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006690 } else {
6691 LY_TREE_FOR(xml->attr, attr) {
6692 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006693 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006694 break;
6695 }
6696 }
6697 assert(attr);
6698 }
Radek Krejcie534c132016-11-23 13:32:31 +01006699 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006700 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006701 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006702 iff_data = str_node;
6703 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006704 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006705 case UNRES_FEATURE:
6706 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6707 ((struct lys_feature *)item)->name);
6708 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006709 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006710 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006711 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006712 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006713 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006714 if (str_node) {
6715 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6716 } /* else no default value in the type itself, but we are checking some restrictions against
6717 * possible default value of some base type. The failure is caused by not resolved base type,
6718 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006719 break;
6720 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006721 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006722 break;
6723 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006724 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006725 break;
6726 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006727 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006728 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006729 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006730 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6731 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006732 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006733 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006734 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6735 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006736 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006737 case UNRES_EXT:
6738 extinfo = (struct unres_ext *)str_node;
6739 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6740 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6741 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006742 default:
6743 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006744 break;
6745 }
6746}
6747
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006748/**
Michal Vaskobb211122015-08-19 14:03:11 +02006749 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006750 *
6751 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006752 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006753 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006754 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006755 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006756int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006757resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006758{
Radek Krejci010e54b2016-03-15 09:40:34 +01006759 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006760 struct lyxml_elem *yin;
6761 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006762 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006763
6764 assert(unres);
6765
Michal Vaskoe8734262016-09-29 14:12:06 +02006766 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko4814fb02017-08-17 14:49:38 +02006767 if (ly_vlog_hidden) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006768 log_hidden = 1;
6769 } else {
6770 log_hidden = 0;
6771 ly_vlog_hide(1);
6772 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006773
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006774 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006775 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006776 unres_count = 0;
6777 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006778
6779 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006780 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006781 * if-features are resolved here to make sure that we will have all if-features for
6782 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006783 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006784 continue;
6785 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006786 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006787 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006788
Michal Vasko88c29542015-11-27 14:57:53 +01006789 ++unres_count;
Michal Vaskof96dfb62017-08-17 12:23:49 +02006790 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006791 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006792 unres->type[i] = UNRES_RESOLVED;
6793 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006794 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006795 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006796 if (!log_hidden) {
6797 ly_vlog_hide(0);
6798 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006799 /* print the error */
Radek Krejcicf748252017-09-04 11:11:14 +02006800 ly_err_repeat(ly_parser_data.ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006801 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006802 } else {
6803 /* forward reference, erase ly_errno */
Radek Krejcicf748252017-09-04 11:11:14 +02006804 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006805 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006806 }
Michal Vasko88c29542015-11-27 14:57:53 +01006807 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006808
Michal Vasko88c29542015-11-27 14:57:53 +01006809 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006810 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006811 if (!log_hidden) {
6812 ly_vlog_hide(0);
6813 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006814
6815 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006816 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006817 continue;
6818 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02006819 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006820 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006821 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6822 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6823 yang =(struct yang_type *)yin;
6824 ((struct lys_type *)unres->item[i])->base = yang->base;
6825 if (yang->base == LY_TYPE_UNION) {
6826 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6827 }
6828 lydict_remove(mod->ctx, yang->name);
6829 free(yang);
6830 } else {
6831 lyxml_free(mod->ctx, yin);
6832 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006833 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006834 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006835 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006836 }
6837
Michal Vaskof96dfb62017-08-17 12:23:49 +02006838 /* the rest except finalizing extensions and xpath */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006839 for (i = 0; i < unres->count; ++i) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02006840 if ((unres->type[i] == UNRES_RESOLVED) || (unres->type[i] == UNRES_EXT_FINALIZE) || (unres->type[i] == UNRES_XPATH)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006841 continue;
6842 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006843
Michal Vaskof96dfb62017-08-17 12:23:49 +02006844 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006845 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006846 if (unres->type[i] == UNRES_LIST_UNIQ) {
6847 /* free the allocated structure */
6848 free(unres->item[i]);
6849 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006850 unres->type[i] = UNRES_RESOLVED;
6851 ++resolved;
6852 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006853 if (!log_hidden) {
6854 ly_vlog_hide(0);
6855 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006856 /* print the error */
Radek Krejcicf748252017-09-04 11:11:14 +02006857 ly_err_repeat(ly_parser_data.ctx);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006858 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006859 } else {
6860 /* forward reference, erase ly_errno */
Radek Krejcicf748252017-09-04 11:11:14 +02006861 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006862 }
6863 }
6864
Michal Vasko74a60c02017-03-08 10:19:48 +01006865 if (!log_hidden) {
6866 ly_vlog_hide(0);
6867 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006868
Radek Krejci80056d52017-01-05 13:13:33 +01006869 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6870 for (i = 0; i < unres->count; ++i) {
6871 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6872 continue;
6873 }
6874
Michal Vaskof96dfb62017-08-17 12:23:49 +02006875 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci791f6c72017-02-22 15:23:39 +01006876 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006877 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006878 ++resolved;
6879 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006880 /* else error - it was already printed, but resolved was not increased,
6881 so this unres item will not be resolved again in the following code,
6882 but it will cause returning -1 at the end, this way we are able to
6883 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006884 }
6885
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006886 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006887 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
Michal Vaskof96dfb62017-08-17 12:23:49 +02006888 * all the validation errors, xpath is resolved only here to properly print all the messages
Radek Krejci010e54b2016-03-15 09:40:34 +01006889 */
6890 for (i = 0; i < unres->count; ++i) {
6891 if (unres->type[i] == UNRES_RESOLVED) {
6892 continue;
6893 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02006894 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01006895 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006896 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006897 unres->type[i] = UNRES_RESOLVED;
6898 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006899 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006900 }
Radek Krejcib3142312016-11-09 11:04:12 +01006901 if (resolved < unres->count) {
6902 return -1;
6903 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006904 }
6905
Michal Vaskoe8734262016-09-29 14:12:06 +02006906 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006907 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006908 return EXIT_SUCCESS;
6909}
6910
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006911/**
Michal Vaskobb211122015-08-19 14:03:11 +02006912 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006913 *
6914 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006915 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006916 * @param[in] item Item to resolve. Type determined by \p type.
6917 * @param[in] type Type of the unresolved item.
6918 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006919 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006920 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006921 */
6922int
Radek Krejci48464ed2016-03-17 15:44:09 +01006923unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6924 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006925{
Radek Krejci54081ce2016-08-12 15:21:47 +02006926 int rc;
6927 const char *dictstr;
6928
6929 dictstr = lydict_insert(mod->ctx, str, 0);
6930 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6931
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006932 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006933 lydict_remove(mod->ctx, dictstr);
6934 }
6935 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006936}
6937
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006938/**
Michal Vaskobb211122015-08-19 14:03:11 +02006939 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006940 *
6941 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006942 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006943 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006944 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006945 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006946 *
Michal Vaskof96dfb62017-08-17 12:23:49 +02006947 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error, -2 if the unres item
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006948 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006949 */
6950int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006951unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006952 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006953{
Michal Vaskoef486d72016-09-27 12:10:44 +02006954 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006955 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006956
Michal Vasko9bf425b2015-10-22 11:42:03 +02006957 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6958 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006959
Michal Vasko9e862e82017-03-08 10:20:49 +01006960#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006961 uint32_t u;
6962
Radek Krejci850a5de2016-11-08 14:06:40 +01006963 /* check for duplicities in unres */
6964 for (u = 0; u < unres->count; u++) {
6965 if (unres->type[u] == type && unres->item[u] == item &&
6966 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006967 /* duplication, should not happen */
6968 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006969 }
6970 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006971#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006972
Michal Vaskof96dfb62017-08-17 12:23:49 +02006973 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH)) {
6974 /* extension finalization is not even tried when adding the item into the inres list,
6975 * xpath is not tried because it would hide some potential warnings */
Radek Krejcic293bac2017-02-27 11:25:28 +01006976 rc = EXIT_FAILURE;
6977 } else {
Michal Vasko4814fb02017-08-17 14:49:38 +02006978 if (ly_vlog_hidden) {
Radek Krejci80056d52017-01-05 13:13:33 +01006979 log_hidden = 1;
6980 } else {
6981 log_hidden = 0;
6982 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006983 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02006984 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01006985 if (!log_hidden) {
6986 ly_vlog_hide(0);
6987 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006988
Radek Krejci80056d52017-01-05 13:13:33 +01006989 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02006990 if (rc == -1) {
Radek Krejcicf748252017-09-04 11:11:14 +02006991 ly_err_repeat(ly_parser_data.ctx);
Radek Krejci80056d52017-01-05 13:13:33 +01006992 }
6993 if (type == UNRES_LIST_UNIQ) {
6994 /* free the allocated structure */
6995 free(item);
6996 } else if (rc == -1 && type == UNRES_IFFEAT) {
6997 /* free the allocated resources */
6998 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02006999 }
Radek Krejci80056d52017-01-05 13:13:33 +01007000 return rc;
7001 } else {
7002 /* erase info about validation errors */
Radek Krejcicf748252017-09-04 11:11:14 +02007003 ly_err_clean(ly_parser_data.ctx, 1);
Radek Krejci80056d52017-01-05 13:13:33 +01007004 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007005
Radek Krejci80056d52017-01-05 13:13:33 +01007006 print_unres_schema_item_fail(item, type, snode);
7007
7008 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7009 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7010 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7011 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7012 lyxml_unlink_elem(mod->ctx, yin, 1);
7013 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7014 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007015 }
Michal Vasko88c29542015-11-27 14:57:53 +01007016 }
7017
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007018 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007019 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007020 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007021 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007022 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007023 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007024 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007025 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007026 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM, -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007027 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007028 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007029 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM, -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007030 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007031
Michal Vasko3767fb22016-07-21 12:10:57 +02007032 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007033}
7034
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007035/**
Michal Vaskobb211122015-08-19 14:03:11 +02007036 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007037 *
7038 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007039 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007040 * @param[in] item Old item to be resolved.
7041 * @param[in] type Type of the old unresolved item.
7042 * @param[in] new_item New item to use in the duplicate.
7043 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007044 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007045 */
Michal Vaskodad19402015-08-06 09:51:53 +02007046int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007047unres_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 +02007048{
7049 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007050 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007051 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007052
Michal Vaskocf024702015-10-08 15:01:42 +02007053 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007054
Radek Krejcid09d1a52016-08-11 14:05:45 +02007055 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7056 if (type == UNRES_LIST_UNIQ) {
7057 aux_uniq.list = item;
7058 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7059 item = &aux_uniq;
7060 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007061 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007062
7063 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007064 if (type == UNRES_LIST_UNIQ) {
7065 free(new_item);
7066 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007067 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007068 }
7069
Radek Krejcic79c6b12016-07-26 15:11:49 +02007070 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007071 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007072 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007073 LOGINT;
7074 return -1;
7075 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007076 } else if (type == UNRES_IFFEAT) {
7077 /* duplicate unres_iffeature_data */
7078 iff_data = malloc(sizeof *iff_data);
Radek Krejciaa1303c2017-05-31 13:57:37 +02007079 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM, -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007080 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7081 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7082 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7083 LOGINT;
7084 return -1;
7085 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007086 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007087 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007088 LOGINT;
7089 return -1;
7090 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007091 }
Michal Vaskodad19402015-08-06 09:51:53 +02007092
7093 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007094}
7095
Michal Vaskof02e3742015-08-05 16:27:02 +02007096/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007097int
Michal Vasko878e38d2016-09-05 12:17:53 +02007098unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007099{
Michal Vasko878e38d2016-09-05 12:17:53 +02007100 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007101 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007102
Radek Krejciddddd0d2017-01-20 15:20:46 +01007103 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007104 i = start_on_backwards;
7105 } else {
7106 i = unres->count - 1;
7107 }
7108 for (; i > -1; i--) {
7109 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007110 continue;
7111 }
7112 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007113 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007114 break;
7115 }
7116 } else {
7117 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7118 aux_uniq2 = (struct unres_list_uniq *)item;
7119 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007120 break;
7121 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007122 }
7123 }
7124
Michal Vasko878e38d2016-09-05 12:17:53 +02007125 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007126}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007127
Michal Vaskoede9c472016-06-07 09:38:15 +02007128static void
7129unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7130{
7131 struct lyxml_elem *yin;
7132 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007133 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007134
7135 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007136 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007137 case UNRES_TYPE_DER:
7138 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7139 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7140 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007141 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007142 lydict_remove(ctx, yang->name);
7143 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007144 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7145 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7146 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007147 } else {
7148 lyxml_free(ctx, yin);
7149 }
7150 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007151 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007152 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7153 lydict_remove(ctx, iff_data->fname);
7154 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007155 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007156 case UNRES_IDENT:
7157 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007158 case UNRES_CHOICE_DFLT:
7159 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007160 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7161 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007162 case UNRES_LIST_UNIQ:
7163 free(unres->item[i]);
7164 break;
PavolVicanc1807262017-01-31 18:00:27 +01007165 case UNRES_EXT:
7166 free(unres->str_snode[i]);
7167 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007168 default:
7169 break;
7170 }
7171 unres->type[i] = UNRES_RESOLVED;
7172}
7173
Michal Vasko88c29542015-11-27 14:57:53 +01007174void
Michal Vasko44ab1462017-05-18 13:18:36 +02007175unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007176{
7177 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007178 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007179
Radek Krejcic071c542016-01-27 14:57:51 +01007180 if (!unres || !(*unres)) {
7181 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007182 }
7183
Michal Vasko44ab1462017-05-18 13:18:36 +02007184 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007185
7186 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007187 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007188 if ((*unres)->type[i] != UNRES_RESOLVED) {
7189 unresolved++;
7190 }
7191 continue;
7192 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007193
7194 /* free heap memory for the specific item */
7195 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007196 }
7197
Michal Vaskoede9c472016-06-07 09:38:15 +02007198 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007199 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007200 free((*unres)->item);
7201 free((*unres)->type);
7202 free((*unres)->str_snode);
7203 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007204 free((*unres));
7205 (*unres) = NULL;
7206 }
Michal Vasko88c29542015-11-27 14:57:53 +01007207}
7208
Michal Vaskoff690e72017-08-03 14:25:07 +02007209/* check whether instance-identifier points outside its data subtree (for operation it is any node
7210 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007211static int
7212check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7213{
Michal Vaskoff690e72017-08-03 14:25:07 +02007214 const struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007215 char *buf;
Michal Vaskoff690e72017-08-03 14:25:07 +02007216 int ret = 0, hidden;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007217
Radek Krejci034cb102017-08-01 15:45:13 +02007218 if (!json_instid || !json_instid[0]) {
7219 /* no/empty value */
7220 return 0;
7221 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007222
7223 for (op_node = lys_parent(sleaf);
7224 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7225 op_node = lys_parent(op_node));
7226
7227 if (op_node && lys_parent(op_node)) {
7228 /* nested operation - any absolute path is external */
7229 return 1;
7230 }
7231
7232 /* get the first node from the instid */
7233 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7234 if (!buf) {
7235 LOGMEM;
7236 return -1;
7237 }
7238
Michal Vaskoff690e72017-08-03 14:25:07 +02007239 /* find the first schema node, do not log */
Michal Vasko4814fb02017-08-17 14:49:38 +02007240 hidden = ly_vlog_hidden;
Michal Vaskoff690e72017-08-03 14:25:07 +02007241 if (!hidden) {
7242 ly_vlog_hide(1);
7243 }
7244 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
7245 if (!hidden) {
7246 ly_vlog_hide(0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007247 }
7248
Michal Vaskoff690e72017-08-03 14:25:07 +02007249 if (!first_node) {
7250 /* unknown path, say it is not external */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007251 free(buf);
Radek Krejci98caa582017-09-07 14:32:56 +02007252 ly_errno = LY_SUCCESS;
Michal Vaskoff690e72017-08-03 14:25:07 +02007253 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007254 }
7255 free(buf);
7256
7257 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7258
Michal Vaskoff690e72017-08-03 14:25:07 +02007259 if (op_node && (op_node != first_node)) {
7260 /* it is a top-level operation, so we're good if it points somewhere inside it */
7261 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007262 }
7263
7264 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7265 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007266 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007267}
7268
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007269/**
7270 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7271 *
7272 * @param[in] data Data node where the path is used
7273 * @param[in] path Instance-identifier node value.
7274 * @param[in,out] ret Resolved instance or NULL.
7275 *
7276 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7277 */
7278static int
7279resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7280{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007281 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007282 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007283 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007284 struct lyd_node *root, *node;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007285 const char *model, *name;
7286 char *str;
7287 int mod_len, name_len, has_predicate;
7288 struct unres_data node_match;
7289
7290 memset(&node_match, 0, sizeof node_match);
7291 *ret = NULL;
7292
7293 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007294 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007295 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007296 if (root->prev) {
7297 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007298 }
7299
7300 /* search for the instance node */
7301 while (path[i]) {
7302 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7303 if (j <= 0) {
7304 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7305 goto error;
7306 }
7307 i += j;
7308
Michal Vasko1b6ca962017-08-03 14:23:09 +02007309 if (model) {
7310 str = strndup(model, mod_len);
7311 if (!str) {
7312 LOGMEM;
7313 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007314 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007315 mod = ly_ctx_get_module(ctx, str, NULL);
7316 if (ctx->data_clb) {
7317 if (!mod) {
7318 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7319 } else if (!mod->implemented) {
7320 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7321 }
7322 }
7323 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007324
Michal Vasko1b6ca962017-08-03 14:23:09 +02007325 if (!mod || !mod->implemented || mod->disabled) {
7326 break;
7327 }
7328 } else if (!prev_mod) {
7329 /* first iteration and we are missing module name */
7330 LOGVAL(LYE_INELEM_LEN, LY_VLOG_NONE, NULL, name_len, name);
7331 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Instane-identifier is missing prefix in the first node.");
7332 goto error;
7333 } else {
7334 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007335 }
7336
Radek Krejci2c822ed2017-08-03 14:23:36 +02007337 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007338 /* no instance exists */
7339 break;
7340 }
7341
7342 if (has_predicate) {
7343 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007344 j = 0;
7345 /* index of the current node (for lists with position predicates) */
7346 cur_idx = 1;
7347 while (j < (signed)node_match.count) {
7348 node = node_match.node[j];
7349 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7350 if (parsed < 1) {
7351 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
7352 goto error;
7353 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007354
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007355 if (!node) {
7356 /* current node does not satisfy the predicate */
7357 unres_data_del(&node_match, j);
7358 } else {
7359 ++j;
7360 }
7361 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007362 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007363
7364 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007365 } else if (node_match.count) {
7366 /* check that we are not addressing lists */
7367 for (j = 0; (unsigned)j < node_match.count; ++j) {
7368 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7369 unres_data_del(&node_match, j--);
7370 }
7371 }
7372 if (!node_match.count) {
Radek Krejci2c822ed2017-08-03 14:23:36 +02007373 LOGVAL(LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007374 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007375 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007376
7377 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007378 }
7379
7380 if (!node_match.count) {
7381 /* no instance exists */
7382 if (req_inst > -1) {
Radek Krejci2c822ed2017-08-03 14:23:36 +02007383 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007384 return EXIT_FAILURE;
7385 }
7386 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7387 return EXIT_SUCCESS;
7388 } else if (node_match.count > 1) {
7389 /* instance identifier must resolve to a single node */
7390 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7391 goto error;
7392 } else {
7393 /* we have required result, remember it and cleanup */
7394 *ret = node_match.node[0];
7395 free(node_match.node);
7396 return EXIT_SUCCESS;
7397 }
7398
7399error:
7400 /* cleanup */
7401 free(node_match.node);
7402 return -1;
7403}
7404
7405static int
7406resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007407{
Michal Vaskoca16cb32017-07-10 11:50:33 +02007408 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007409 uint32_t i;
7410
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007411 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007412
Michal Vaskoca16cb32017-07-10 11:50:33 +02007413 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007414 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vaskoca16cb32017-07-10 11:50:33 +02007415 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007416 return -1;
7417 }
7418
Michal Vaskoca16cb32017-07-10 11:50:33 +02007419 for (i = 0; i < set->number; ++i) {
7420 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7421 continue;
7422 }
7423
Radek Krejci1899d6a2016-11-03 13:48:07 +01007424 /* not that the value is already in canonical form since the parsers does the conversion,
7425 * so we can simply compare just the values */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007426 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)set->set.d[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007427 /* we have the match */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007428 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007429 break;
7430 }
7431 }
7432
Michal Vaskoca16cb32017-07-10 11:50:33 +02007433 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007434
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007435 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007436 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007437 if (req_inst > -1) {
7438 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007439 return EXIT_FAILURE;
7440 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007441 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 +02007442 }
7443 }
7444
7445 return EXIT_SUCCESS;
7446}
7447
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007448/* 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 +01007449int
7450resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7451 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007452{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007453 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007454 struct lyd_node *ret;
7455 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007456 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007457
7458 assert(type->base == LY_TYPE_UNION);
7459
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007460 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7461 /* either NULL or instid previously converted to JSON */
7462 json_val = leaf->value.string;
7463 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007464
Michal Vaskofd6c6502017-01-06 12:15:41 +01007465 if (store) {
7466 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7467 free(leaf->value.bit);
7468 }
7469 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007470 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007471
7472 /* turn logging off, we are going to try to validate the value with all the types in order */
Michal Vasko4814fb02017-08-17 14:49:38 +02007473 hidden = ly_vlog_hidden;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007474 ly_vlog_hide(1);
7475
7476 t = NULL;
7477 found = 0;
7478 while ((t = lyp_get_next_union_type(type, t, &found))) {
7479 found = 0;
7480
7481 switch (t->base) {
7482 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007483 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7484 req_inst = -1;
7485 } else {
7486 req_inst = t->info.lref.req;
7487 }
7488
7489 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007490 if (store) {
7491 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7492 /* valid resolved */
7493 leaf->value.leafref = ret;
7494 leaf->value_type = LY_TYPE_LEAFREF;
7495 } else {
7496 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007497 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007498 return -1;
7499 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007500 }
7501 }
7502
7503 success = 1;
7504 }
7505 break;
7506 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007507 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
Radek Krejci034cb102017-08-01 15:45:13 +02007508 if (ext_dep == -1) {
7509 return -1;
7510 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007511 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 */
Radek Krejcicf748252017-09-04 11:11:14 +02007558 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007559
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 Vasko0b963112017-08-11 12:45:36 +02007609resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail, struct lys_when **failed_when)
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 Vasko0b963112017-08-11 12:45:36 +02007684 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
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 Vasko0b963112017-08-11 12:45:36 +02007760 struct lys_when *when;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007761
Radek Krejci082c84f2016-10-17 16:33:06 +02007762 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007763 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007764
7765 if (!unres->count) {
7766 return EXIT_SUCCESS;
7767 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007768
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007769 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 +01007770 ignore_fail = 1;
7771 } else if (options & LYD_OPT_NOEXTDEPS) {
7772 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007773 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007774 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007775 }
7776
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007777 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007778 ly_vlog_hide(1);
7779
Radek Krejci0b7704f2016-03-18 12:16:14 +01007780 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007781 first = 1;
7782 stmt_count = 0;
7783 resolved = 0;
7784 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007785 do {
Radek Krejcicf748252017-09-04 11:11:14 +02007786 ly_err_clean(ly_parser_data.ctx, 1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007787 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007788 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007789 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007790 continue;
7791 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007792 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007793 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007794 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007795 }
7796
7797 /* resolve when condition only when all parent when conditions are already resolved */
7798 for (parent = unres->node[i]->parent;
7799 parent && LYD_WHEN_DONE(parent->when_status);
7800 parent = parent->parent) {
7801 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7802 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02007803 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01007804 */
7805 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7806 unres->type[i] = UNRES_RESOLVED;
7807 resolved++;
7808 break;
7809 }
7810 }
7811 if (parent) {
7812 continue;
7813 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007814
Michal Vasko0b963112017-08-11 12:45:36 +02007815 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01007816 if (!rc) {
Michal Vasko0b963112017-08-11 12:45:36 +02007817 /* finish with error/delete the node only if when was false, an external dependency was not required,
7818 * or it was not provided (the flag would not be passed down otherwise, checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02007819 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vasko0b963112017-08-11 12:45:36 +02007820 && (!(when->flags & LYS_XPATH_DEP) || !(options & LYD_OPT_NOEXTDEPS))) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007821 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007822 /* false when condition */
7823 ly_vlog_hide(0);
Radek Krejcicf748252017-09-04 11:11:14 +02007824 ly_err_repeat(ly_parser_data.ctx);
Radek Krejci03b71f72016-03-16 11:10:09 +01007825 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007826 } /* follows else */
7827
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007828 /* auto-delete */
7829 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7830 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7831
Radek Krejci0c0086a2016-03-24 15:20:28 +01007832 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7833 /* if it has parent non-presence containers that would be empty, we should actually
7834 * remove the container
7835 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007836 for (parent = unres->node[i];
7837 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7838 parent = parent->parent) {
7839 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7840 /* presence container */
7841 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007842 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007843 if (parent->next || parent->prev != parent) {
7844 /* non empty (the child we are in and we are going to remove is not the only child) */
7845 break;
7846 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007847 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007848 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007849
Radek Krejci0c0086a2016-03-24 15:20:28 +01007850 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007851 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007852 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007853
Radek Krejci0b7704f2016-03-18 12:16:14 +01007854 lyd_unlink(unres->node[i]);
7855 unres->type[i] = UNRES_DELETE;
7856 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007857
7858 /* update the rest of unres items */
7859 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007860 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007861 continue;
7862 }
7863
7864 /* test if the node is in subtree to be deleted */
7865 for (parent = unres->node[j]; parent; parent = parent->parent) {
7866 if (parent == unres->node[i]) {
7867 /* yes, it is */
7868 unres->type[j] = UNRES_RESOLVED;
7869 resolved++;
7870 break;
7871 }
7872 }
7873 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007874 } else {
7875 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007876 }
Radek Krejcicf748252017-09-04 11:11:14 +02007877 ly_err_clean(ly_parser_data.ctx, 1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007878 resolved++;
7879 progress = 1;
7880 } else if (rc == -1) {
7881 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007882 /* print only this last error */
Michal Vasko0b963112017-08-11 12:45:36 +02007883 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Radek Krejci010e54b2016-03-15 09:40:34 +01007884 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007885 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007886 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007887 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007888 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007889
Radek Krejci0b7704f2016-03-18 12:16:14 +01007890 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007891 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007892 ly_vlog_hide(0);
Radek Krejcicf748252017-09-04 11:11:14 +02007893 ly_err_repeat(ly_parser_data.ctx);
Radek Krejci0b7704f2016-03-18 12:16:14 +01007894 return -1;
7895 }
7896
7897 for (i = 0; del_items && i < unres->count; i++) {
7898 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7899 if (unres->type[i] != UNRES_DELETE) {
7900 continue;
7901 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007902 if (!unres->node[i]) {
7903 unres->type[i] = UNRES_RESOLVED;
7904 del_items--;
7905 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007906 }
7907
7908 /* really remove the complete subtree */
7909 lyd_free(unres->node[i]);
7910 unres->type[i] = UNRES_RESOLVED;
7911 del_items--;
7912 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007913
7914 /* now leafrefs */
7915 first = 1;
7916 stmt_count = 0;
7917 resolved = 0;
7918 do {
7919 progress = 0;
7920 for (i = 0; i < unres->count; i++) {
7921 if (unres->type[i] != UNRES_LEAFREF) {
7922 continue;
7923 }
7924 if (first) {
7925 /* count leafref nodes in unres list */
7926 stmt_count++;
7927 }
7928
Michal Vasko0b963112017-08-11 12:45:36 +02007929 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007930 if (!rc) {
7931 unres->type[i] = UNRES_RESOLVED;
Radek Krejcicf748252017-09-04 11:11:14 +02007932 ly_err_clean(ly_parser_data.ctx, 1);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007933 resolved++;
7934 progress = 1;
7935 } else if (rc == -1) {
7936 ly_vlog_hide(0);
7937 /* print only this last error */
Michal Vasko0b963112017-08-11 12:45:36 +02007938 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007939 return -1;
7940 } /* else forward reference */
7941 }
7942 first = 0;
7943 } while (progress && resolved < stmt_count);
7944
7945 /* do we have some unresolved leafrefs? */
7946 if (stmt_count > resolved) {
7947 ly_vlog_hide(0);
Radek Krejcicf748252017-09-04 11:11:14 +02007948 ly_err_repeat(ly_parser_data.ctx);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007949 return -1;
7950 }
7951
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007952 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007953
7954 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007955 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007956 if (unres->type[i] == UNRES_RESOLVED) {
7957 continue;
7958 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007959 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007960
Michal Vasko0b963112017-08-11 12:45:36 +02007961 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007962 if (rc) {
7963 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007964 return -1;
7965 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007966
7967 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007968 }
7969
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007970 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007971 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007972 return EXIT_SUCCESS;
7973}