blob: f3d630433966e13d2e0af76df707629e8a9913df [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 *
Michal Vasko53b7da02018-02-13 15:28:42 +01006 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
Michal Vasko730dfdf2015-08-11 14:48:05 +02007 *
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 Vasko53b7da02018-02-13 15:28:42 +01001145 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146 return -1;
1147 }
1148
Michal Vasko921eb6b2017-10-13 10:01:39 +02001149 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001150 if (!module) {
1151 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01001152 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001153 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);
Michal Vasko53b7da02018-02-13 15:28:42 +01001203 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001204 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);
Michal Vasko53b7da02018-02-13 15:28:42 +01001280 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); 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 Vasko53b7da02018-02-13 15:28:42 +01001396 struct ly_ctx *ctx = node->module->ctx;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001397
Radek Krejci9ff0a922016-07-14 13:08:05 +02001398 assert(c);
1399
1400 if (isspace(c[0])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001401 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001402 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001403 }
1404
Radek Krejci9ff0a922016-07-14 13:08:05 +02001405 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1406 for (i = j = last_not = 0; c[i]; i++) {
1407 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001408 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001409 j++;
1410 continue;
1411 } else if (c[i] == ')') {
1412 j--;
1413 continue;
1414 } else if (isspace(c[i])) {
1415 continue;
1416 }
1417
1418 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1419 if (c[i + r] == '\0') {
Michal Vasko53b7da02018-02-13 15:28:42 +01001420 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001421 return EXIT_FAILURE;
1422 } else if (!isspace(c[i + r])) {
1423 /* feature name starting with the not/and/or */
1424 last_not = 0;
1425 f_size++;
1426 } else if (c[i] == 'n') { /* not operation */
1427 if (last_not) {
1428 /* double not */
1429 expr_size = expr_size - 2;
1430 last_not = 0;
1431 } else {
1432 last_not = 1;
1433 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001434 } else { /* and, or */
1435 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001436 /* not a not operation */
1437 last_not = 0;
1438 }
1439 i += r;
1440 } else {
1441 f_size++;
1442 last_not = 0;
1443 }
1444 expr_size++;
1445
1446 while (!isspace(c[i])) {
1447 if (!c[i] || c[i] == ')') {
1448 i--;
1449 break;
1450 }
1451 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001452 }
1453 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001454 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001455 /* not matching count of ( and ) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001456 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001457 return EXIT_FAILURE;
1458 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001459
Radek Krejci69b8d922016-07-27 13:13:41 +02001460 if (checkversion || expr_size > 1) {
1461 /* check that we have 1.1 module */
1462 if (node->module->version != 2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001463 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1464 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
Radek Krejci69b8d922016-07-27 13:13:41 +02001465 return EXIT_FAILURE;
1466 }
1467 }
1468
Radek Krejci9ff0a922016-07-14 13:08:05 +02001469 /* allocate the memory */
1470 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001471 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001472 stack.stack = malloc(expr_size * sizeof *stack.stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001473 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001474 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001475 f_size--; expr_size--; /* used as indexes from now */
1476
1477 for (i--; i >= 0; i--) {
1478 if (c[i] == ')') {
1479 /* push it on stack */
1480 iff_stack_push(&stack, LYS_IFF_RP);
1481 continue;
1482 } else if (c[i] == '(') {
1483 /* pop from the stack into result all operators until ) */
1484 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1485 iff_setop(iffeat_expr->expr, op, expr_size--);
1486 }
1487 continue;
1488 } else if (isspace(c[i])) {
1489 continue;
1490 }
1491
1492 /* end operator or operand -> find beginning and get what is it */
1493 j = i + 1;
1494 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1495 i--;
1496 }
1497 i++; /* get back by one step */
1498
1499 if (!strncmp(&c[i], "not ", 4)) {
1500 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1501 /* double not */
1502 iff_stack_pop(&stack);
1503 } else {
1504 /* not has the highest priority, so do not pop from the stack
1505 * as in case of AND and OR */
1506 iff_stack_push(&stack, LYS_IFF_NOT);
1507 }
1508 } else if (!strncmp(&c[i], "and ", 4)) {
1509 /* as for OR - pop from the stack all operators with the same or higher
1510 * priority and store them to the result, then push the AND to the stack */
1511 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1512 op = iff_stack_pop(&stack);
1513 iff_setop(iffeat_expr->expr, op, expr_size--);
1514 }
1515 iff_stack_push(&stack, LYS_IFF_AND);
1516 } else if (!strncmp(&c[i], "or ", 3)) {
1517 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1518 op = iff_stack_pop(&stack);
1519 iff_setop(iffeat_expr->expr, op, expr_size--);
1520 }
1521 iff_stack_push(&stack, LYS_IFF_OR);
1522 } else {
1523 /* feature name, length is j - i */
1524
1525 /* add it to the result */
1526 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1527
1528 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001529 * forward referenced, we have to keep the feature name in auxiliary
1530 * structure passed into unres */
1531 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01001532 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001533 iff_data->node = node;
1534 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001535 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001536 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1537 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001538 f_size--;
1539
1540 if (r == -1) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01001541 lydict_remove(node->module->ctx, iff_data->fname);
Pavol Vican4d084512016-09-29 16:38:12 +02001542 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001543 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001544 }
1545 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001546 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001547 while (stack.index) {
1548 op = iff_stack_pop(&stack);
1549 iff_setop(iffeat_expr->expr, op, expr_size--);
1550 }
1551
1552 if (++expr_size || ++f_size) {
1553 /* not all expected operators and operands found */
Michal Vasko53b7da02018-02-13 15:28:42 +01001554 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001555 rc = EXIT_FAILURE;
1556 } else {
1557 rc = EXIT_SUCCESS;
1558 }
1559
1560error:
1561 /* cleanup */
1562 iff_stack_clean(&stack);
1563
1564 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001565}
1566
1567/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001568 * @brief Resolve (find) a data node based on a schema-nodeid.
1569 *
1570 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1571 * module).
1572 *
1573 */
1574struct lyd_node *
1575resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1576{
1577 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001578 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001579 const struct lys_node *schema = NULL;
1580
1581 assert(nodeid && start);
1582
1583 if (nodeid[0] == '/') {
1584 return NULL;
1585 }
1586
1587 str = p = strdup(nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01001588 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001589
Michal Vasko3edeaf72016-02-11 13:17:43 +01001590 while (p) {
1591 token = p;
1592 p = strchr(p, '/');
1593 if (p) {
1594 *p = '\0';
1595 p++;
1596 }
1597
Radek Krejci5da4eb62016-04-08 14:45:51 +02001598 if (p) {
1599 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001600 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001601 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001602 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001603 result = NULL;
1604 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001605 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001606
Radek Krejci5da4eb62016-04-08 14:45:51 +02001607 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1608 continue;
1609 }
1610 } else {
1611 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001612 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001613 || !schema) {
1614 result = NULL;
1615 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001616 }
1617 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001618 LY_TREE_FOR(result ? result->child : start, iter) {
1619 if (iter->schema == schema) {
1620 /* move in data tree according to returned schema */
1621 result = iter;
1622 break;
1623 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001624 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001625 if (!iter) {
1626 /* instance not found */
1627 result = NULL;
1628 break;
1629 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001630 }
1631 free(str);
1632
1633 return result;
1634}
1635
Radek Krejci1a9c3612017-04-24 14:49:43 +02001636int
Michal Vasko50576712017-07-28 12:28:33 +02001637schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1638 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001639{
1640 const struct lys_module *prefix_mod;
1641
Michal Vaskocdb3f062018-02-01 09:55:06 +01001642 /* handle special names */
1643 if (name[0] == '*') {
1644 return 2;
1645 } else if (name[0] == '.') {
1646 return 3;
1647 }
1648
Michal Vasko50576712017-07-28 12:28:33 +02001649 /* name check */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001650 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02001651 return 1;
1652 }
1653
Radek Krejcibdf92362016-04-08 14:43:34 +02001654 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001655 if (mod_name) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001656 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vasko50576712017-07-28 12:28:33 +02001657 if (!prefix_mod) {
1658 return -1;
1659 }
1660 } else {
1661 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001662 }
1663 if (prefix_mod != lys_node_module(sibling)) {
1664 return 1;
1665 }
1666
Michal Vasko50576712017-07-28 12:28:33 +02001667 /* match */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001668 return 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001669}
1670
Michal Vasko50576712017-07-28 12:28:33 +02001671/* keys do not have to be ordered and do not have to be all of them */
1672static int
1673resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1674 const struct lys_module *cur_module, int *nodeid_end)
1675{
1676 int mod_len, nam_len, has_predicate, r, i;
1677 const char *model, *name;
1678 struct lys_node_list *list;
1679
1680 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1681 return 1;
1682 }
1683
1684 list = (struct lys_node_list *)node;
1685 do {
1686 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1687 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001688 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001689 return -1;
1690 }
1691 nodeid += r;
1692
1693 if (node->nodetype == LYS_LEAFLIST) {
1694 /* just check syntax */
1695 if (model || !name || (name[0] != '.') || has_predicate) {
1696 return 1;
1697 }
1698 break;
1699 } else {
1700 /* check the key */
1701 for (i = 0; i < list->keys_size; ++i) {
1702 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1703 continue;
1704 }
1705 if (model) {
1706 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1707 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1708 continue;
1709 }
1710 } else {
1711 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1712 continue;
1713 }
1714 }
1715
1716 /* match */
1717 break;
1718 }
1719
1720 if (i == list->keys_size) {
1721 return 1;
1722 }
1723 }
1724 } while (has_predicate);
1725
1726 if (!nodeid[0]) {
1727 *nodeid_end = 1;
1728 }
1729 return 0;
1730}
1731
Michal Vasko97234262018-02-01 09:53:01 +01001732/* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001733 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001734int
Michal Vasko97234262018-02-01 09:53:01 +01001735resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
Michal Vasko50576712017-07-28 12:28:33 +02001736 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001737{
Michal Vaskobb520442017-05-23 10:55:18 +02001738 const char *name, *mod_name, *id;
Michal Vasko97234262018-02-01 09:53:01 +01001739 const struct lys_node *sibling, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001740 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001741 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 +01001742 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidaa547a2017-09-22 15:56:27 +02001743 const struct lys_module *start_mod, *aux_mod = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02001744 char *str;
Michal Vasko53b7da02018-02-13 15:28:42 +01001745 struct ly_ctx *ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001746
Michal Vasko97234262018-02-01 09:53:01 +01001747 assert(nodeid && (start_parent || cur_module) && ret);
Michal Vasko50576712017-07-28 12:28:33 +02001748 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001749
Michal Vasko50576712017-07-28 12:28:33 +02001750 if (!cur_module) {
Michal Vasko97234262018-02-01 09:53:01 +01001751 cur_module = lys_node_module(start_parent);
Michal Vasko50576712017-07-28 12:28:33 +02001752 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001753 ctx = cur_module->ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001754 id = nodeid;
1755
Michal Vasko50576712017-07-28 12:28:33 +02001756 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1757 (extended ? &all_desc : NULL), extended);
1758 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001759 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001760 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001761 }
1762 id += r;
1763
Michal Vasko97234262018-02-01 09:53:01 +01001764 if (is_relative && !start_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001765 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
Michal Vasko3edeaf72016-02-11 13:17:43 +01001766 return -1;
1767 }
1768
1769 /* descendant-schema-nodeid */
1770 if (is_relative) {
Michal Vasko97234262018-02-01 09:53:01 +01001771 cur_module = start_mod = lys_node_module(start_parent);
Michal Vasko24476fa2017-03-08 12:33:48 +01001772
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 /* absolute-schema-nodeid */
1774 } else {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001775 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01001776 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001777 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001778 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001779 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001780 return -1;
1781 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001782 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001783 }
1784
1785 while (1) {
1786 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001787 last_aug = NULL;
1788
1789 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001790 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1791 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001792 /* we are getting into another module (augment) */
Michal Vasko921eb6b2017-10-13 10:01:39 +02001793 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskobb520442017-05-23 10:55:18 +02001794 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001795 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001796 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001797 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001798 return -1;
1799 }
1800 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001801 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001802 * because this module may be not implemented and it augments something in another module and
1803 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001804 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001805 }
1806
1807 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001808 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001809get_next_augment:
1810 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1811 }
1812 }
1813
1814 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vaskocb45f472018-02-12 10:47:42 +01001815 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02001816 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1817
1818 /* resolve predicate */
1819 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1820 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1821 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001822 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001823 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001824 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001825 }
Michal Vasko50576712017-07-28 12:28:33 +02001826 } else if (!id[0]) {
1827 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001828 }
Michal Vasko50576712017-07-28 12:28:33 +02001829
1830 if (r == 0) {
1831 /* one matching result */
1832 if (nodeid_end) {
1833 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001834 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001835 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1836 } else {
1837 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1838 return -1;
1839 }
1840 start_parent = sibling;
1841 }
1842 break;
1843 } else if (r == 1) {
1844 continue;
1845 } else if (r == 2) {
1846 /* "*" */
1847 if (!*ret) {
1848 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001849 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001850 }
1851 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1852 if (all_desc) {
1853 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1854 if (elem != sibling) {
1855 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1856 }
1857
1858 LY_TREE_DFS_END(sibling, next, elem);
1859 }
1860 }
1861 } else if (r == 3) {
1862 /* "." */
1863 if (!*ret) {
1864 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001865 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001866 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1867 }
1868 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1869 if (all_desc) {
1870 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1871 if (elem != sibling) {
1872 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1873 }
1874
1875 LY_TREE_DFS_END(sibling, next, elem);
1876 }
1877 }
1878 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001879 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001880 return -1;
1881 }
1882 }
1883
1884 /* skip predicate */
1885 if (extended && has_predicate) {
1886 while (id[0] == '[') {
1887 id = strchr(id, ']');
1888 if (!id) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001889 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001890 return -1;
1891 }
1892 ++id;
1893 }
1894 }
1895
1896 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1897 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001898 }
1899
1900 /* no match */
1901 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001902 if (last_aug) {
1903 /* it still could be in another augment */
1904 goto get_next_augment;
1905 }
Michal Vasko50576712017-07-28 12:28:33 +02001906 if (no_node_error) {
1907 str = strndup(nodeid, (name - nodeid) + nam_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001908 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001909 free(str);
1910 return -1;
1911 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001912 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001913 return EXIT_SUCCESS;
1914 }
1915
Michal Vasko50576712017-07-28 12:28:33 +02001916 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1917 (extended ? &all_desc : NULL), extended);
1918 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001919 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001920 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001921 }
1922 id += r;
1923 }
1924
1925 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01001926 LOGINT(ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001927 return -1;
1928}
1929
Radek Krejcif3c71de2016-04-11 12:45:46 +02001930/* unique, refine,
1931 * >0 - unexpected char on position (ret - 1),
1932 * 0 - ok (but ret can still be NULL),
1933 * -1 - error,
1934 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001935int
1936resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001937 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938{
1939 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001940 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 int r, nam_len, mod_name_len, is_relative = -1;
1942 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001943 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001944
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001945 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001946 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001947
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001948 if (!start) {
1949 /* leaf not found */
1950 return 0;
1951 }
1952
Michal Vasko3edeaf72016-02-11 13:17:43 +01001953 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02001954 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001955
Michal Vasko50576712017-07-28 12:28:33 +02001956 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 +01001957 return ((id - nodeid) - r) + 1;
1958 }
1959 id += r;
1960
1961 if (!is_relative) {
1962 return -1;
1963 }
1964
Michal Vasko24476fa2017-03-08 12:33:48 +01001965 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001966 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001967 start_parent = lys_parent(start_parent);
1968 }
1969
Michal Vasko3edeaf72016-02-11 13:17:43 +01001970 while (1) {
1971 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001972 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vaskocb45f472018-02-12 10:47:42 +01001973 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02001974 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
1975 if (r == 0) {
1976 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001977 if (!(sibling->nodetype & ret_nodetype)) {
1978 /* wrong node type, too bad */
1979 continue;
1980 }
1981 *ret = sibling;
1982 return EXIT_SUCCESS;
1983 }
Michal Vasko50576712017-07-28 12:28:33 +02001984 start_parent = sibling;
1985 break;
1986 } else if (r == 1) {
1987 continue;
1988 } else {
1989 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001990 }
1991 }
1992
1993 /* no match */
1994 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001995 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001996 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001997 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1998 *ret = NULL;
1999 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002000 }
2001
Michal Vasko50576712017-07-28 12:28:33 +02002002 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 +01002003 return ((id - nodeid) - r) + 1;
2004 }
2005 id += r;
2006 }
2007
2008 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002009 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002010 return -1;
2011}
2012
2013/* choice default */
2014int
2015resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2016{
2017 /* cannot actually be a path */
2018 if (strchr(nodeid, '/')) {
2019 return -1;
2020 }
2021
Michal Vaskodc300b02017-04-07 14:09:20 +02002022 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002023}
2024
2025/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2026static int
2027resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2028{
2029 const struct lys_module *module;
2030 const char *mod_prefix, *name;
2031 int i, mod_prefix_len, nam_len;
2032
2033 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002034 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 +01002035 return -i + 1;
2036 }
2037
Michal Vasko921eb6b2017-10-13 10:01:39 +02002038 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002039 if (!module) {
2040 return -1;
2041 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002042 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002043 start = module->data;
2044 }
2045
2046 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2047
2048 return EXIT_SUCCESS;
2049}
2050
2051int
2052resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2053 const struct lys_node **ret)
2054{
2055 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002056 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002057 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002058 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002059
2060 assert(nodeid && module && ret);
2061 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2062
2063 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002064 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002065
Michal Vasko50576712017-07-28 12:28:33 +02002066 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 +01002067 return ((id - nodeid) - r) + 1;
2068 }
2069 id += r;
2070
2071 if (is_relative) {
2072 return -1;
2073 }
2074
Michal Vasko921eb6b2017-10-13 10:01:39 +02002075 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01002076 if (!abs_start_mod) {
2077 return -1;
2078 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002079
2080 while (1) {
2081 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002082 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vaskocb45f472018-02-12 10:47:42 +01002083 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002084 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2085 if (r == 0) {
2086 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002087 if (!(sibling->nodetype & ret_nodetype)) {
2088 /* wrong node type, too bad */
2089 continue;
2090 }
2091 *ret = sibling;
2092 return EXIT_SUCCESS;
2093 }
Michal Vasko50576712017-07-28 12:28:33 +02002094 start_parent = sibling;
2095 break;
2096 } else if (r == 1) {
2097 continue;
2098 } else {
2099 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002100 }
2101 }
2102
2103 /* no match */
2104 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002105 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002106 return EXIT_SUCCESS;
2107 }
2108
Michal Vasko50576712017-07-28 12:28:33 +02002109 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 +01002110 return ((id - nodeid) - r) + 1;
2111 }
2112 id += r;
2113 }
2114
2115 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002116 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002117 return -1;
2118}
2119
Michal Vaskoe733d682016-03-14 09:08:27 +01002120static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002121resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002122{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002123 const char *mod_name, *name;
2124 int mod_name_len, nam_len, has_predicate, i;
2125 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002126
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002127 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 +02002128 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002129 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002130 return -1;
2131 }
2132
2133 predicate += i;
2134 *parsed += i;
2135
Michal Vasko58c2aab2017-01-05 10:02:05 +01002136 if (!isdigit(name[0])) {
2137 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002138 key = (struct lys_node *)list->keys[i];
2139 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002140 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002141 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002142 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002143
Michal Vasko58c2aab2017-01-05 10:02:05 +01002144 if (i == list->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002145 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko58c2aab2017-01-05 10:02:05 +01002146 return -1;
2147 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002148 }
2149
2150 /* more predicates? */
2151 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002152 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002153 }
2154
2155 return 0;
2156}
2157
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002158/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002159const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002160resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002161{
Michal Vasko53b7da02018-02-13 15:28:42 +01002162 char *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002163 const char *name, *mod_name, *id;
Michal Vaskob3744402017-08-03 14:23:58 +02002164 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002165 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002166 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002167 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002168
Michal Vasko3547c532016-03-14 09:40:50 +01002169 assert(nodeid && (ctx || start));
2170 if (!ctx) {
2171 ctx = start->module->ctx;
2172 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002173
2174 id = nodeid;
2175
Michal Vasko50576712017-07-28 12:28:33 +02002176 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002177 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002178 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002179 }
2180 id += r;
2181
2182 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002183 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002184 start_parent = start;
2185 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2186 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002187 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002188 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002189 } else {
2190 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002191 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002192 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
Michal Vasko10728b52016-04-07 14:26:29 +02002193 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002194 return NULL;
2195 }
2196
Michal Vasko53b7da02018-02-13 15:28:42 +01002197 str = strndup(mod_name, mod_name_len);
2198 module = ly_ctx_get_module(ctx, str, NULL, 1);
2199 free(str);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002200
Michal Vaskof68a49e2017-08-14 13:23:37 +02002201 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002202 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002203 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002204 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002205 return NULL;
2206 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002207 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002208
2209 /* now it's as if there was no module name */
2210 mod_name = NULL;
2211 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002212 }
2213
Michal Vaskof68a49e2017-08-14 13:23:37 +02002214 prev_mod = module;
2215
Michal Vasko3edeaf72016-02-11 13:17:43 +01002216 while (1) {
2217 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002218 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002219 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002220 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002221 /* output check */
2222 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2223 if (parent) {
2224 if (output && (parent->nodetype == LYS_INPUT)) {
2225 continue;
2226 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2227 continue;
2228 }
2229 }
2230
Michal Vasko3edeaf72016-02-11 13:17:43 +01002231 /* module check */
2232 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002233 /* will also find an augment module */
Michal Vasko53b7da02018-02-13 15:28:42 +01002234 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002235
Michal Vasko3edeaf72016-02-11 13:17:43 +01002236 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002237 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002238 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002239 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002240 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002241 }
2242 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002243 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002244 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002245 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002246 continue;
2247 }
2248
Michal Vaskoe733d682016-03-14 09:08:27 +01002249 /* do we have some predicates on it? */
2250 if (has_predicate) {
2251 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002252 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002253 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002254 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002255 return NULL;
2256 }
2257 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002258 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002259 return NULL;
2260 }
2261 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002262 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002263 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002264 }
2265 id += r;
2266 }
2267
Michal Vasko3edeaf72016-02-11 13:17:43 +01002268 /* the result node? */
2269 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002270 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002271 }
2272
Michal Vaskodc300b02017-04-07 14:09:20 +02002273 /* move down the tree, if possible */
2274 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002275 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskodc300b02017-04-07 14:09:20 +02002276 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002277 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002278 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002279
2280 /* update prev mod */
2281 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002282 break;
2283 }
2284 }
2285
2286 /* no match */
2287 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002288 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002289 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002290 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002291 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002292 }
2293
Michal Vasko50576712017-07-28 12:28:33 +02002294 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002295 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002296 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002297 }
2298 id += r;
2299 }
2300
2301 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002302 LOGINT(ctx);
Michal Vaskoe733d682016-03-14 09:08:27 +01002303 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002304}
2305
Michal Vasko22448d32016-03-16 13:17:29 +01002306static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002307resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko50576712017-07-28 12:28:33 +02002308 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002309{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002310 const char *mod_name, *name, *value, *key_val;
2311 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002312 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002313 struct lyd_node_leaf_list *key;
Michal Vasko53b7da02018-02-13 15:28:42 +01002314 struct ly_ctx *ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002315
Radek Krejci61a86c62016-03-24 11:06:44 +01002316 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002317 assert(node->schema->nodetype == LYS_LIST);
Michal Vasko53b7da02018-02-13 15:28:42 +01002318 ctx = node->schema->module->ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002319
Michal Vasko53adfc72017-01-06 10:39:10 +01002320 /* is the predicate a number? */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002321 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 +01002322 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002323 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vasko53adfc72017-01-06 10:39:10 +01002324 return -1;
2325 }
2326
2327 if (isdigit(name[0])) {
2328 if (position == atoi(name)) {
2329 /* match */
2330 *parsed += r;
2331 return 0;
2332 } else {
2333 /* not a match */
2334 return 1;
2335 }
2336 }
2337
2338 if (!((struct lys_node_list *)node->schema)->keys_size) {
2339 /* no keys in schema - causes an error later */
2340 return 0;
2341 }
2342
Michal Vaskof29903d2016-04-18 13:13:10 +02002343 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002344 if (!key) {
2345 /* it is not a position, so we need a key for it to be a match */
2346 return 1;
2347 }
2348
2349 /* go through all the keys */
2350 i = 0;
2351 goto check_parsed_values;
2352
2353 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002354 if (!has_predicate) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002355 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002356 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002357 }
2358
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002359 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 +02002360 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002361 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002362 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002363 }
2364
Michal Vasko53adfc72017-01-06 10:39:10 +01002365check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002366 predicate += r;
2367 *parsed += r;
2368
Michal Vaskof29903d2016-04-18 13:13:10 +02002369 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002370 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002371 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002372 }
2373
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002374 if (mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002375 /* specific module, check that the found key is from that module */
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002376 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2377 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002378 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002379 return -1;
2380 }
Michal Vasko50576712017-07-28 12:28:33 +02002381
2382 /* but if the module is the same as the parent, it should have been omitted */
2383 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002384 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko50576712017-07-28 12:28:33 +02002385 return -1;
2386 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002387 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002388 /* no module, so it must be the same as the list (parent) */
2389 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002390 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002391 return -1;
2392 }
2393 }
2394
Michal Vasko9ba34de2016-12-07 12:21:19 +01002395 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002396 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002397 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2398 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002399 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2400 } else {
2401 key_val = key->value_str;
2402 }
2403
Michal Vasko22448d32016-03-16 13:17:29 +01002404 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002405 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002406 return 1;
2407 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002408
2409 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002410 }
2411
2412 if (has_predicate) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002413 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002414 return -1;
2415 }
2416
2417 return 0;
2418}
2419
Radek Krejci45826012016-08-24 15:07:57 +02002420/**
2421 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2422 *
2423 * @param[in] nodeid Node data path to find
2424 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2425 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2426 * @param[out] parsed Number of characters processed in \p id
2427 * @return The closes parent (or the node itself) from the path
2428 */
Michal Vasko22448d32016-03-16 13:17:29 +01002429struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002430resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2431 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002432{
Michal Vasko53b7da02018-02-13 15:28:42 +01002433 char *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002434 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002435 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002436 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002437 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002438 struct lyd_node_leaf_list *llist;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002439 const struct lys_module *prefix_mod, *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002440 struct ly_ctx *ctx;
2441
2442 assert(nodeid && start && parsed);
2443
2444 ctx = start->schema->module->ctx;
2445 id = nodeid;
2446
Michal Vasko50576712017-07-28 12:28:33 +02002447 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002448 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002449 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002450 return NULL;
2451 }
2452 id += r;
2453 /* add it to parsed only after the data node was actually found */
2454 last_parsed = r;
2455
2456 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002457 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002458 start = start->child;
2459 } else {
2460 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002461 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002462 }
2463
2464 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002465 list_instance_position = 0;
2466
Michal Vasko22448d32016-03-16 13:17:29 +01002467 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002468 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002469 if (lys_parent(sibling->schema)) {
2470 if (options & LYD_PATH_OPT_OUTPUT) {
2471 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002472 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002473 *parsed = -1;
2474 return NULL;
2475 }
2476 } else {
2477 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002478 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002479 *parsed = -1;
2480 return NULL;
2481 }
2482 }
2483 }
2484
Michal Vasko22448d32016-03-16 13:17:29 +01002485 /* name match */
2486 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2487
2488 /* module check */
2489 if (mod_name) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002490 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002491
Michal Vasko22448d32016-03-16 13:17:29 +01002492 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002493 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002494 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002495 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002496 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002497 return NULL;
2498 }
2499 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002500 prefix_mod = prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002501 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002502 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002503 continue;
2504 }
2505
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002506 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002507 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002508 llist = (struct lyd_node_leaf_list *)sibling;
2509
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002510 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002511 if (has_predicate) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002512 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2513 &llval_len, &last_has_pred)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002514 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskof0a50972016-10-19 11:33:55 +02002515 *parsed = -1;
2516 return NULL;
2517 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002518 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002519 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002520 *parsed = -1;
2521 return NULL;
2522 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002523 } else {
2524 r = 0;
2525 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002526 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002527 }
2528 }
2529
Michal Vasko21b90ce2017-09-19 09:38:27 +02002530 /* make value canonical (remove module name prefix) unless it was specified with it */
Michal Vaskod6d51292017-09-22 14:30:48 +02002531 if (llist_value && !strchr(llist_value, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002532 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2533 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002534 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2535 } else {
2536 data_val = llist->value_str;
2537 }
2538
2539 if ((!llist_value && data_val && data_val[0])
2540 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002541 continue;
2542 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002543
Michal Vaskof0a50972016-10-19 11:33:55 +02002544 id += r;
2545 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002546 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002547
Radek Krejci45826012016-08-24 15:07:57 +02002548 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002549 /* 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 +01002550 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002551 /* none match */
2552 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002553 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002554
2555 ++list_instance_position;
2556 r = 0;
Michal Vasko50576712017-07-28 12:28:33 +02002557 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002558 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002559 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002560 return NULL;
2561 } else if (ret == 1) {
2562 /* this list instance does not match */
2563 continue;
2564 }
2565 id += r;
2566 last_parsed += r;
2567 }
2568
2569 *parsed += last_parsed;
2570
2571 /* the result node? */
2572 if (!id[0]) {
2573 return sibling;
2574 }
2575
2576 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002577 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002578 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002579 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002580 return NULL;
2581 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002582 last_match = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002583 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002584 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002585 break;
2586 }
2587 }
2588
2589 /* no match, return last match */
2590 if (!sibling) {
2591 return last_match;
2592 }
2593
Michal Vasko50576712017-07-28 12:28:33 +02002594 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002595 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002596 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002597 return NULL;
2598 }
2599 id += r;
2600 last_parsed = r;
2601 }
2602
2603 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002604 LOGINT(ctx);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002605 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002606 return NULL;
2607}
2608
Michal Vasko3edeaf72016-02-11 13:17:43 +01002609/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002610 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002611 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002612 *
Michal Vasko53b7da02018-02-13 15:28:42 +01002613 * @param[in] ctx Context for errors.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002614 * @param[in] str_restr Restriction as a string.
2615 * @param[in] type Type of the restriction.
2616 * @param[out] ret Final interval structure that starts with
2617 * the interval of the initial type, continues with intervals
2618 * of any superior types derived from the initial one, and
2619 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002620 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002621 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002622 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002623int
Michal Vasko53b7da02018-02-13 15:28:42 +01002624resolve_len_ran_interval(struct ly_ctx *ctx, const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625{
2626 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002627 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002628 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002629 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002630 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002631 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002632 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002633
2634 switch (type->base) {
2635 case LY_TYPE_BINARY:
2636 kind = 0;
2637 local_umin = 0;
2638 local_umax = 18446744073709551615UL;
2639
2640 if (!str_restr && type->info.binary.length) {
2641 str_restr = type->info.binary.length->expr;
2642 }
2643 break;
2644 case LY_TYPE_DEC64:
2645 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002646 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2647 local_fmax = __INT64_C(9223372036854775807);
2648 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002649
2650 if (!str_restr && type->info.dec64.range) {
2651 str_restr = type->info.dec64.range->expr;
2652 }
2653 break;
2654 case LY_TYPE_INT8:
2655 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002656 local_smin = __INT64_C(-128);
2657 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002658
2659 if (!str_restr && type->info.num.range) {
2660 str_restr = type->info.num.range->expr;
2661 }
2662 break;
2663 case LY_TYPE_INT16:
2664 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002665 local_smin = __INT64_C(-32768);
2666 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002667
2668 if (!str_restr && type->info.num.range) {
2669 str_restr = type->info.num.range->expr;
2670 }
2671 break;
2672 case LY_TYPE_INT32:
2673 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002674 local_smin = __INT64_C(-2147483648);
2675 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002676
2677 if (!str_restr && type->info.num.range) {
2678 str_restr = type->info.num.range->expr;
2679 }
2680 break;
2681 case LY_TYPE_INT64:
2682 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002683 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2684 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002685
2686 if (!str_restr && type->info.num.range) {
2687 str_restr = type->info.num.range->expr;
2688 }
2689 break;
2690 case LY_TYPE_UINT8:
2691 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002692 local_umin = __UINT64_C(0);
2693 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002694
2695 if (!str_restr && type->info.num.range) {
2696 str_restr = type->info.num.range->expr;
2697 }
2698 break;
2699 case LY_TYPE_UINT16:
2700 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002701 local_umin = __UINT64_C(0);
2702 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002703
2704 if (!str_restr && type->info.num.range) {
2705 str_restr = type->info.num.range->expr;
2706 }
2707 break;
2708 case LY_TYPE_UINT32:
2709 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002710 local_umin = __UINT64_C(0);
2711 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002712
2713 if (!str_restr && type->info.num.range) {
2714 str_restr = type->info.num.range->expr;
2715 }
2716 break;
2717 case LY_TYPE_UINT64:
2718 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002719 local_umin = __UINT64_C(0);
2720 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002721
2722 if (!str_restr && type->info.num.range) {
2723 str_restr = type->info.num.range->expr;
2724 }
2725 break;
2726 case LY_TYPE_STRING:
2727 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002728 local_umin = __UINT64_C(0);
2729 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002730
2731 if (!str_restr && type->info.str.length) {
2732 str_restr = type->info.str.length->expr;
2733 }
2734 break;
2735 default:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002736 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002737 }
2738
2739 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002740 if (type->der) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002741 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002742 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002743 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002744 assert(!intv || (intv->kind == kind));
2745 }
2746
2747 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002748 /* we do not have any restriction, return superior ones */
2749 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002750 return EXIT_SUCCESS;
2751 }
2752
2753 /* adjust local min and max */
2754 if (intv) {
2755 tmp_intv = intv;
2756
2757 if (kind == 0) {
2758 local_umin = tmp_intv->value.uval.min;
2759 } else if (kind == 1) {
2760 local_smin = tmp_intv->value.sval.min;
2761 } else if (kind == 2) {
2762 local_fmin = tmp_intv->value.fval.min;
2763 }
2764
2765 while (tmp_intv->next) {
2766 tmp_intv = tmp_intv->next;
2767 }
2768
2769 if (kind == 0) {
2770 local_umax = tmp_intv->value.uval.max;
2771 } else if (kind == 1) {
2772 local_smax = tmp_intv->value.sval.max;
2773 } else if (kind == 2) {
2774 local_fmax = tmp_intv->value.fval.max;
2775 }
2776 }
2777
2778 /* finally parse our restriction */
2779 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002780 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002781 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002782 if (!tmp_local_intv) {
2783 assert(!local_intv);
2784 local_intv = malloc(sizeof *local_intv);
2785 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002786 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002787 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002788 tmp_local_intv = tmp_local_intv->next;
2789 }
Michal Vasko53b7da02018-02-13 15:28:42 +01002790 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002791
2792 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002793 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002794 tmp_local_intv->next = NULL;
2795
2796 /* min */
2797 ptr = seg_ptr;
2798 while (isspace(ptr[0])) {
2799 ++ptr;
2800 }
2801 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2802 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002803 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002804 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002805 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002806 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002807 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002808 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02002809 goto error;
2810 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002811 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002812 } else if (!strncmp(ptr, "min", 3)) {
2813 if (kind == 0) {
2814 tmp_local_intv->value.uval.min = local_umin;
2815 } else if (kind == 1) {
2816 tmp_local_intv->value.sval.min = local_smin;
2817 } else if (kind == 2) {
2818 tmp_local_intv->value.fval.min = local_fmin;
2819 }
2820
2821 ptr += 3;
2822 } else if (!strncmp(ptr, "max", 3)) {
2823 if (kind == 0) {
2824 tmp_local_intv->value.uval.min = local_umax;
2825 } else if (kind == 1) {
2826 tmp_local_intv->value.sval.min = local_smax;
2827 } else if (kind == 2) {
2828 tmp_local_intv->value.fval.min = local_fmax;
2829 }
2830
2831 ptr += 3;
2832 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002833 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002834 }
2835
2836 while (isspace(ptr[0])) {
2837 ptr++;
2838 }
2839
2840 /* no interval or interval */
2841 if ((ptr[0] == '|') || !ptr[0]) {
2842 if (kind == 0) {
2843 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2844 } else if (kind == 1) {
2845 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2846 } else if (kind == 2) {
2847 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2848 }
2849 } else if (!strncmp(ptr, "..", 2)) {
2850 /* skip ".." */
2851 ptr += 2;
2852 while (isspace(ptr[0])) {
2853 ++ptr;
2854 }
2855
2856 /* max */
2857 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2858 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002859 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002860 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002861 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002862 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002863 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002864 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02002865 goto error;
2866 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002867 }
2868 } else if (!strncmp(ptr, "max", 3)) {
2869 if (kind == 0) {
2870 tmp_local_intv->value.uval.max = local_umax;
2871 } else if (kind == 1) {
2872 tmp_local_intv->value.sval.max = local_smax;
2873 } else if (kind == 2) {
2874 tmp_local_intv->value.fval.max = local_fmax;
2875 }
2876 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002877 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002878 }
2879 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002880 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002881 }
2882
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002883 /* check min and max in correct order*/
2884 if (kind == 0) {
2885 /* current segment */
2886 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2887 goto error;
2888 }
2889 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2890 goto error;
2891 }
2892 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002893 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002894 goto error;
2895 }
2896 } else if (kind == 1) {
2897 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2898 goto error;
2899 }
2900 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2901 goto error;
2902 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002903 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002904 goto error;
2905 }
2906 } else if (kind == 2) {
2907 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2908 goto error;
2909 }
2910 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2911 goto error;
2912 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002913 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002914 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002915 goto error;
2916 }
2917 }
2918
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002919 /* next segment (next OR) */
2920 seg_ptr = strchr(seg_ptr, '|');
2921 if (!seg_ptr) {
2922 break;
2923 }
2924 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002925 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002926 }
2927
2928 /* check local restrictions against superior ones */
2929 if (intv) {
2930 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002931 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002932
2933 while (tmp_local_intv && tmp_intv) {
2934 /* reuse local variables */
2935 if (kind == 0) {
2936 local_umin = tmp_local_intv->value.uval.min;
2937 local_umax = tmp_local_intv->value.uval.max;
2938
2939 /* it must be in this interval */
2940 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2941 /* this interval is covered, next one */
2942 if (local_umax <= tmp_intv->value.uval.max) {
2943 tmp_local_intv = tmp_local_intv->next;
2944 continue;
2945 /* ascending order of restrictions -> fail */
2946 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002947 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002948 }
2949 }
2950 } else if (kind == 1) {
2951 local_smin = tmp_local_intv->value.sval.min;
2952 local_smax = tmp_local_intv->value.sval.max;
2953
2954 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2955 if (local_smax <= tmp_intv->value.sval.max) {
2956 tmp_local_intv = tmp_local_intv->next;
2957 continue;
2958 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002959 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002960 }
2961 }
2962 } else if (kind == 2) {
2963 local_fmin = tmp_local_intv->value.fval.min;
2964 local_fmax = tmp_local_intv->value.fval.max;
2965
Michal Vasko4d1f0482016-09-19 14:35:06 +02002966 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002967 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002968 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002969 tmp_local_intv = tmp_local_intv->next;
2970 continue;
2971 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002972 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002973 }
2974 }
2975 }
2976
2977 tmp_intv = tmp_intv->next;
2978 }
2979
2980 /* some interval left uncovered -> fail */
2981 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002982 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002983 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002984 }
2985
Michal Vaskoaeb51802016-04-11 10:58:47 +02002986 /* append the local intervals to all the intervals of the superior types, return it all */
2987 if (intv) {
2988 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2989 tmp_intv->next = local_intv;
2990 } else {
2991 intv = local_intv;
2992 }
2993 *ret = intv;
2994
2995 return EXIT_SUCCESS;
2996
2997error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002998 while (intv) {
2999 tmp_intv = intv->next;
3000 free(intv);
3001 intv = tmp_intv;
3002 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003003 while (local_intv) {
3004 tmp_local_intv = local_intv->next;
3005 free(local_intv);
3006 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003007 }
3008
Michal Vaskoaeb51802016-04-11 10:58:47 +02003009 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003010}
3011
Michal Vasko730dfdf2015-08-11 14:48:05 +02003012/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003013 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3014 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003015 *
3016 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003017 * @param[in] mod_name Typedef name module name.
3018 * @param[in] module Main module.
3019 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003020 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003021 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003022 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003023 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003024int
Michal Vasko1e62a092015-12-01 12:27:20 +01003025resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3026 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003027{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003028 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003029 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003030 int tpdf_size;
3031
Michal Vasko1dca6882015-10-22 14:29:42 +02003032 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003033 /* no prefix, try built-in types */
3034 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003035 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003036 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003037 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003038 }
3039 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003040 }
3041 }
3042 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003043 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003044 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003045 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003046 }
3047 }
3048
Michal Vasko1dca6882015-10-22 14:29:42 +02003049 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003050 /* search in local typedefs */
3051 while (parent) {
3052 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003053 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003054 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3055 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003056 break;
3057
Radek Krejci76512572015-08-04 09:47:08 +02003058 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003059 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3060 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003061 break;
3062
Radek Krejci76512572015-08-04 09:47:08 +02003063 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003064 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3065 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003066 break;
3067
Radek Krejci76512572015-08-04 09:47:08 +02003068 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003069 case LYS_ACTION:
3070 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3071 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003072 break;
3073
Radek Krejci76512572015-08-04 09:47:08 +02003074 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003075 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3076 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003077 break;
3078
Radek Krejci76512572015-08-04 09:47:08 +02003079 case LYS_INPUT:
3080 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003081 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3082 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003083 break;
3084
3085 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003086 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003087 continue;
3088 }
3089
3090 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003091 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003092 match = &tpdf[i];
3093 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094 }
3095 }
3096
Michal Vaskodcf98e62016-05-05 17:53:53 +02003097 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003098 }
Radek Krejcic071c542016-01-27 14:57:51 +01003099 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003100 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003101 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003102 if (!module) {
3103 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003104 }
3105 }
3106
3107 /* search in top level typedefs */
3108 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003109 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003110 match = &module->tpdf[i];
3111 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003112 }
3113 }
3114
3115 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003116 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003117 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003118 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 +02003119 match = &module->inc[i].submodule->tpdf[j];
3120 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003121 }
3122 }
3123 }
3124
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003125 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003126
3127check_leafref:
3128 if (ret) {
3129 *ret = match;
3130 }
3131 if (match->type.base == LY_TYPE_LEAFREF) {
3132 while (!match->type.info.lref.path) {
3133 match = match->type.der;
3134 assert(match);
3135 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003136 }
3137 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138}
3139
Michal Vasko1dca6882015-10-22 14:29:42 +02003140/**
3141 * @brief Check the default \p value of the \p type. Logs directly.
3142 *
3143 * @param[in] type Type definition to use.
3144 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003145 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003146 *
3147 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3148 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003149static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003150check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151{
Radek Krejcibad2f172016-08-02 11:04:15 +02003152 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003153 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003154 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003155 char *s;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003156 int ret = EXIT_SUCCESS, r;
Michal Vasko53b7da02018-02-13 15:28:42 +01003157 struct ly_ctx *ctx = module->ctx;
Michal Vasko1dca6882015-10-22 14:29:42 +02003158
Radek Krejci51673202016-11-01 17:00:32 +01003159 assert(value);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003160 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003161
Radek Krejcic13db382016-08-16 10:52:42 +02003162 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003163 /* the type was not resolved yet, nothing to do for now */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003164 ret = EXIT_FAILURE;
3165 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003166 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003167 /* do not check defaults in not implemented module's data */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003168 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003169 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003170 /* identityrefs are checked when instantiated in data instead of typedef,
3171 * but in typedef the value has to be modified to include the prefix */
3172 if (*value) {
3173 if (strchr(*value, ':')) {
3174 dflt = transform_schema2json(module, *value);
3175 } else {
3176 /* default prefix of the module where the typedef is defined */
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003177 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3178 LOGMEM(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003179 ret = -1;
3180 goto cleanup;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003181 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003182 dflt = lydict_insert_zc(ctx, s);
Radek Krejci9e6af732017-04-27 14:40:25 +02003183 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003184 lydict_remove(ctx, *value);
Radek Krejci9e6af732017-04-27 14:40:25 +02003185 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003186 dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003187 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003188 goto cleanup;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003189 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3190 /* leafref in typedef cannot be checked */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003191 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003192 }
3193
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003194 dflt = lydict_insert(ctx, *value, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003195 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003196 /* we do not have a new default value, so is there any to check even, in some base type? */
3197 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3198 if (base_tpdf->dflt) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003199 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
Michal Vasko478c4652016-07-21 12:55:01 +02003200 break;
3201 }
3202 }
3203
Radek Krejci51673202016-11-01 17:00:32 +01003204 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003205 /* no default value, nothing to check, all is well */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003206 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003207 }
3208
3209 /* 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)? */
3210 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003211 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003212 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003213 goto cleanup;
Radek Krejci9e6af732017-04-27 14:40:25 +02003214 } else {
3215 /* check the default value from typedef, but use also the typedef's module
3216 * due to possible searching in imported modules which is expected in
3217 * typedef's module instead of module where the typedef is used */
3218 module = base_tpdf->module;
3219 }
3220 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003221 case LY_TYPE_INST:
3222 case LY_TYPE_LEAFREF:
3223 case LY_TYPE_BOOL:
3224 case LY_TYPE_EMPTY:
3225 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003226 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003227 case LY_TYPE_BITS:
3228 /* the default value must match the restricted list of values, if the type was restricted */
3229 if (type->info.bits.count) {
3230 break;
3231 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003232 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003233 case LY_TYPE_ENUM:
3234 /* the default value must match the restricted list of values, if the type was restricted */
3235 if (type->info.enums.count) {
3236 break;
3237 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003238 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003239 case LY_TYPE_DEC64:
3240 if (type->info.dec64.range) {
3241 break;
3242 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003243 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003244 case LY_TYPE_BINARY:
3245 if (type->info.binary.length) {
3246 break;
3247 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003248 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003249 case LY_TYPE_INT8:
3250 case LY_TYPE_INT16:
3251 case LY_TYPE_INT32:
3252 case LY_TYPE_INT64:
3253 case LY_TYPE_UINT8:
3254 case LY_TYPE_UINT16:
3255 case LY_TYPE_UINT32:
3256 case LY_TYPE_UINT64:
3257 if (type->info.num.range) {
3258 break;
3259 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003260 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003261 case LY_TYPE_STRING:
3262 if (type->info.str.length || type->info.str.patterns) {
3263 break;
3264 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003265 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003266 case LY_TYPE_UNION:
3267 /* way too much trouble learning whether we need to check the default again, so just do it */
3268 break;
3269 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01003270 LOGINT(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003271 ret = -1;
3272 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003273 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003274 } else if (type->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003275 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3276 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003277 ret = -1;
3278 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003279 }
3280
Michal Vasko1dca6882015-10-22 14:29:42 +02003281 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003282 memset(&node, 0, sizeof node);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003283 node.value_str = lydict_insert(ctx, dflt, 0);
Michal Vasko1dca6882015-10-22 14:29:42 +02003284 node.value_type = type->base;
Michal Vasko31a2d322018-01-12 13:36:12 +01003285
3286 if (tpdf) {
3287 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003288 if (!node.schema) {
3289 LOGMEM(ctx);
3290 ret = -1;
3291 goto cleanup;
3292 }
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003293 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003294 if (r == -1) {
3295 LOGMEM(ctx);
3296 ret = -1;
3297 goto cleanup;
3298 }
Michal Vasko31a2d322018-01-12 13:36:12 +01003299 node.schema->module = module;
3300 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3301 } else {
3302 node.schema = (struct lys_node *)type->parent;
3303 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003304
Radek Krejci37b756f2016-01-18 10:15:03 +01003305 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003306 if (!type->info.lref.target) {
3307 ret = EXIT_FAILURE;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003308 goto cleanup;
Michal Vasko1dca6882015-10-22 14:29:42 +02003309 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003310 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003311 if (!ret) {
3312 /* adopt possibly changed default value to its canonical form */
3313 if (*value) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003314 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003315 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003316 dflt = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003317 }
3318 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003319 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01003320 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003321 /* possible forward reference */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003322 ret = EXIT_FAILURE;
Radek Krejcibad2f172016-08-02 11:04:15 +02003323 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003324 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003325 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3326 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3327 /* we have refined bits/enums */
Michal Vasko53b7da02018-02-13 15:28:42 +01003328 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
Radek Krejcibad2f172016-08-02 11:04:15 +02003329 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003330 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003331 }
3332 }
Radek Krejci51673202016-11-01 17:00:32 +01003333 } else {
3334 /* success - adopt canonical form from the node into the default value */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003335 if (!ly_strequal(dflt, node.value_str, 1)) {
Radek Krejci51673202016-11-01 17:00:32 +01003336 /* this can happen only if we have non-inherited default value,
3337 * inherited default values are already in canonical form */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003338 assert(ly_strequal(dflt, *value, 1));
3339
3340 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003341 *value = node.value_str;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003342 node.value_str = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003343 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003344 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003345 }
3346
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003347cleanup:
Michal Vasko1dca6882015-10-22 14:29:42 +02003348 if (node.value_type == LY_TYPE_BITS) {
3349 free(node.value.bit);
3350 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003351 lydict_remove(ctx, node.value_str);
3352 if (tpdf && node.schema) {
Michal Vasko31a2d322018-01-12 13:36:12 +01003353 free((char *)node.schema->name);
3354 free(node.schema);
3355 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003356 lydict_remove(ctx, dflt);
Michal Vasko1dca6882015-10-22 14:29:42 +02003357
3358 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003359}
3360
Michal Vasko730dfdf2015-08-11 14:48:05 +02003361/**
3362 * @brief Check a key for mandatory attributes. Logs directly.
3363 *
3364 * @param[in] key The key to check.
3365 * @param[in] flags What flags to check.
3366 * @param[in] list The list of all the keys.
3367 * @param[in] index Index of the key in the key list.
3368 * @param[in] name The name of the keys.
3369 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003370 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003371 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003372 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003373static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003374check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003375{
Radek Krejciadb57612016-02-16 13:34:34 +01003376 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377 char *dup = NULL;
3378 int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01003379 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003380
3381 /* existence */
3382 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003383 if (name[len] != '\0') {
3384 dup = strdup(name);
Michal Vasko53b7da02018-02-13 15:28:42 +01003385 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003386 dup[len] = '\0';
3387 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003388 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003389 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003390 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003391 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 }
3393
3394 /* uniqueness */
3395 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003396 if (key == list->keys[j]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003397 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003398 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 }
3400 }
3401
3402 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003403 if (key->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003404 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003405 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003406 }
3407
3408 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003409 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003410 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003411 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003412 }
3413
3414 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003415 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003416 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003417 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003418 }
3419
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003420 /* key is not placed from augment */
3421 if (key->parent->nodetype == LYS_AUGMENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003422 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3423 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003424 return -1;
3425 }
3426
Radek Krejci3f21ada2016-08-01 13:34:31 +02003427 /* key is not when/if-feature -conditional */
3428 j = 0;
3429 if (key->when || (key->iffeature_size && (j = 1))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003430 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3431 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003432 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003433 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003434 }
3435
Michal Vasko0b85aa82016-03-07 14:37:43 +01003436 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003437}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003438
3439/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003440 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003441 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003442 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003443 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003444 *
3445 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3446 */
3447int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003448resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003449{
Radek Krejci581ce772015-11-10 17:22:40 +01003450 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003451 const struct lys_node *leaf = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01003452 struct ly_ctx *ctx = parent->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453
Michal Vaskodc300b02017-04-07 14:09:20 +02003454 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003455 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003456 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003457 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003458 if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003459 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003460 } else if (rc == -2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003461 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003462 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003463 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003464 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003465 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3466 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003467 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003468 }
Radek Krejci581ce772015-11-10 17:22:40 +01003469 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003471 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003472 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3473 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003474 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003475 }
3476
Radek Krejcicf509982015-12-15 09:22:44 +01003477 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003478 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3479 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003480 return -1;
3481 }
3482
Radek Krejcid09d1a52016-08-11 14:05:45 +02003483 /* check that all unique's targets are of the same config type */
3484 if (*trg_type) {
3485 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003486 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3487 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003488 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3489 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3490 return -1;
3491 }
3492 } else {
3493 /* first unique */
3494 if (leaf->flags & LYS_CONFIG_W) {
3495 *trg_type = 1;
3496 } else {
3497 *trg_type = 2;
3498 }
3499 }
3500
Radek Krejcica7efb72016-01-18 13:06:01 +01003501 /* set leaf's unique flag */
3502 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3503
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504 return EXIT_SUCCESS;
3505
3506error:
3507
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509}
3510
Radek Krejci0c0086a2016-03-24 15:20:28 +01003511void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003512unres_data_del(struct unres_data *unres, uint32_t i)
3513{
3514 /* there are items after the one deleted */
3515 if (i+1 < unres->count) {
3516 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003517 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003518
3519 /* deleting the last item */
3520 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003521 free(unres->node);
3522 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003523 }
3524
3525 /* if there are no items after and it is not the last one, just move the counter */
3526 --unres->count;
3527}
3528
Michal Vasko0491ab32015-08-19 14:28:29 +02003529/**
3530 * @brief Resolve (find) a data node from a specific module. Does not log.
3531 *
3532 * @param[in] mod Module to search in.
3533 * @param[in] name Name of the data node.
3534 * @param[in] nam_len Length of the name.
3535 * @param[in] start Data node to start the search from.
3536 * @param[in,out] parents Resolved nodes. If there are some parents,
3537 * they are replaced (!!) with the resolvents.
3538 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003539 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003540 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003541static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003542resolve_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 +02003543{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003544 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003545 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547
Michal Vasko23b61ec2015-08-19 11:19:50 +02003548 if (!parents->count) {
3549 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003550 parents->node = malloc(sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003551 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003552 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003553 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003554 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003555 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003556 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003557 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 continue;
3559 }
3560 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003561 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003562 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003563 && node->schema->name[nam_len] == '\0') {
3564 /* matching target */
3565 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003566 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003567 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568 flag = 1;
3569 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003570 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003571 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003572 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003573 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003574 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003575 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576 }
3577 }
3578 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003579
3580 if (!flag) {
3581 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003582 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003583 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003584 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003585 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 }
3587
Michal Vasko0491ab32015-08-19 14:28:29 +02003588 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003589}
3590
Michal Vaskoe27516a2016-10-10 17:55:31 +00003591static int
Michal Vasko1c007172017-03-10 10:20:44 +01003592resolve_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 +00003593{
3594 int dep1, dep2;
3595 const struct lys_node *node;
3596
3597 if (lys_parent(op_node)) {
3598 /* inner operation (notif/action) */
3599 if (abs_path) {
3600 return 1;
3601 } else {
3602 /* compare depth of both nodes */
3603 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3604 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3605 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3606 return 1;
3607 }
3608 }
3609 } else {
3610 /* top-level operation (notif/rpc) */
3611 if (op_node != first_node) {
3612 return 1;
3613 }
3614 }
3615
3616 return 0;
3617}
3618
Michal Vasko730dfdf2015-08-11 14:48:05 +02003619/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003620 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003621 *
Michal Vaskobb211122015-08-19 14:03:11 +02003622 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003623 * @param[in] context_node Predicate context node (where the predicate is placed).
3624 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003625 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003626 *
Michal Vasko184521f2015-09-24 13:14:26 +02003627 * @return 0 on forward reference, otherwise the number
3628 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003629 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003630 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003631static int
Michal Vasko1c007172017-03-10 10:20:44 +01003632resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3633 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003634{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003635 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003636 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003637 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003638 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3639 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003640 struct ly_ctx *ctx = context_node->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003641
3642 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003643 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003644 &pke_len, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003645 LOGVAL(ctx, LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003646 return -parsed+i;
3647 }
3648 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003649 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003650
Michal Vasko58090902015-08-13 14:04:15 +02003651 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003652 if (sour_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003653 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003654 } else {
3655 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003656 }
Michal Vaskobb520442017-05-23 10:55:18 +02003657 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003658 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003659 LOGVAL(ctx, LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003660 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003661 }
3662
3663 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003664 dest_parent_times = 0;
3665 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003666 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3667 &dest_parent_times)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003668 LOGVAL(ctx, 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 +02003669 return -parsed;
3670 }
3671 pke_parsed += i;
3672
Radek Krejciadb57612016-02-16 13:34:34 +01003673 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003674 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3675 && !((struct lys_node_augment *)dst_node->parent)->target) {
3676 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003677 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003678 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3679 return 0;
3680 }
3681
Michal Vaskofbaead72016-10-07 10:54:48 +02003682 /* path is supposed to be evaluated in data tree, so we have to skip
3683 * all schema nodes that cannot be instantiated in data tree */
3684 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003685 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003686 dst_node = lys_parent(dst_node));
3687
Michal Vasko1f76a282015-08-04 16:16:53 +02003688 if (!dst_node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003689 LOGVAL(ctx, LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003690 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003691 }
3692 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003693 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003694 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003695 if (dest_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003696 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003697 } else {
3698 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003699 }
Michal Vaskobb520442017-05-23 10:55:18 +02003700 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 +02003701 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003702 LOGVAL(ctx, LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003703 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003704 }
3705
Michal Vaskoe27516a2016-10-10 17:55:31 +00003706 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003707 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003708 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003709 }
3710 first_iter = 0;
3711 }
3712
Michal Vasko1f76a282015-08-04 16:16:53 +02003713 if (pke_len == pke_parsed) {
3714 break;
3715 }
3716
Michal Vaskobb520442017-05-23 10:55:18 +02003717 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 +02003718 &dest_parent_times)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003719 LOGVAL(ctx, LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003720 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003721 return -parsed;
3722 }
3723 pke_parsed += i;
3724 }
3725
3726 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003727 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003728 LOGVAL(ctx, LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
3729 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003730 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003731 return -parsed;
3732 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003733 } while (has_predicate);
3734
3735 return parsed;
3736}
3737
Michal Vasko730dfdf2015-08-11 14:48:05 +02003738/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003739 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003740 *
Michal Vaskobb211122015-08-19 14:03:11 +02003741 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003742 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003743 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003744 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003745 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003746 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003747static int
Michal Vasko1c007172017-03-10 10:20:44 +01003748resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003749{
Michal Vaskocb45f472018-02-12 10:47:42 +01003750 const struct lys_node *node, *op_node = NULL, *tmp_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02003751 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003752 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02003753 const char *id, *prefix, *name;
3754 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskocb45f472018-02-12 10:47:42 +01003755 int i, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003756 struct ly_ctx *ctx = parent->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003757
Michal Vasko184521f2015-09-24 13:14:26 +02003758 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 parent_times = 0;
3760 id = path;
3761
Michal Vasko1c007172017-03-10 10:20:44 +01003762 /* find operation schema we are in */
3763 for (op_node = lys_parent(parent);
3764 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3765 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003766
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003767 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003769 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003770 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003771 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 }
3773 id += i;
3774
Michal Vaskobb520442017-05-23 10:55:18 +02003775 /* get the current module */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003776 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003777 if (!tmp_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003778 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vaskobb520442017-05-23 10:55:18 +02003779 return EXIT_FAILURE;
3780 }
3781 last_aug = NULL;
3782
Michal Vasko184521f2015-09-24 13:14:26 +02003783 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003784 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003785 /* use module data */
3786 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003787
Michal Vasko1f76a282015-08-04 16:16:53 +02003788 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003789 /* we are looking for the right parent */
3790 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003791 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
3792 && !((struct lys_node_augment *)node->parent)->target) {
3793 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003794 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003795 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
3796 return EXIT_FAILURE;
3797 }
3798
Radek Krejci3a5501d2016-07-18 22:03:34 +02003799 /* path is supposed to be evaluated in data tree, so we have to skip
3800 * all schema nodes that cannot be instantiated in data tree */
3801 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003802 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003803 node = lys_parent(node));
3804
Michal Vasko1f76a282015-08-04 16:16:53 +02003805 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003806 if (i == parent_times - 1) {
3807 /* top-level */
3808 break;
3809 }
3810
3811 /* higher than top-level */
Michal Vasko53b7da02018-02-13 15:28:42 +01003812 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003814 }
3815 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003816 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003817 LOGINT(ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003818 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003819 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003820 }
3821
Michal Vaskobb520442017-05-23 10:55:18 +02003822 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3823 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003824 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003825get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003826 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02003827 }
3828
Michal Vaskocb45f472018-02-12 10:47:42 +01003829 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
3830 node = NULL;
3831 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
3832 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
3833 continue;
3834 }
3835 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
3836 continue;
3837 }
3838 /* match */
3839 break;
3840 }
3841 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003842 if (last_aug) {
3843 goto get_next_augment;
3844 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003845 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003846 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003847 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003848
Michal Vaskoe27516a2016-10-10 17:55:31 +00003849 if (first_iter) {
3850 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003851 if (op_node && parent_times &&
3852 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003853 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003854 }
3855 first_iter = 0;
3856 }
3857
Michal Vasko1f76a282015-08-04 16:16:53 +02003858 if (has_predicate) {
3859 /* we have predicate, so the current result must be list */
3860 if (node->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003861 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003862 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003863 }
3864
Michal Vasko1c007172017-03-10 10:20:44 +01003865 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003866 if (!i) {
3867 return EXIT_FAILURE;
3868 } else if (i < 0) {
3869 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003870 }
3871 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003872 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003873 }
3874 } while (id[0]);
3875
Michal Vaskoca917682016-07-25 11:00:37 +02003876 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003877 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003878 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3879 LOGVAL(ctx, 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 +02003880 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003881 }
3882
Radek Krejcicf509982015-12-15 09:22:44 +01003883 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003884 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003885 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003886 return -1;
3887 }
3888
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003889 if (ret) {
3890 *ret = node;
3891 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003892
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003893 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003894}
3895
Michal Vasko730dfdf2015-08-11 14:48:05 +02003896/**
Michal Vasko718ecdd2017-10-03 14:12:39 +02003897 * @brief Compare 2 data node values.
3898 *
3899 * Comparison performed on canonical forms, the first value
3900 * is first transformed into canonical form.
3901 *
3902 * @param[in] node Leaf/leaf-list with these values.
3903 * @param[in] noncan_val Non-canonical value.
3904 * @param[in] noncan_val_len Length of \p noncal_val.
3905 * @param[in] can_val Canonical value.
3906 * @return 1 if equal, 0 if not, -1 on error (logged).
3907 */
3908static int
3909valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
3910{
3911 int ret;
3912 struct lyd_node_leaf_list leaf;
3913 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
3914
3915 /* dummy leaf */
3916 memset(&leaf, 0, sizeof leaf);
3917 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
3918
3919repeat:
3920 leaf.value_type = sleaf->type.base;
3921 leaf.schema = node;
3922
3923 if (leaf.value_type == LY_TYPE_LEAFREF) {
3924 if (!sleaf->type.info.lref.target) {
3925 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01003926 LOGINT(node->module->ctx);
Michal Vasko718ecdd2017-10-03 14:12:39 +02003927 ret = -1;
3928 goto finish;
3929 }
3930 sleaf = sleaf->type.info.lref.target;
3931 goto repeat;
3932 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01003933 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
Michal Vasko718ecdd2017-10-03 14:12:39 +02003934 ret = -1;
3935 goto finish;
3936 }
3937 }
3938
3939 if (!strcmp(leaf.value_str, can_val)) {
3940 ret = 1;
3941 } else {
3942 ret = 0;
3943 }
3944
3945finish:
3946 lydict_remove(node->module->ctx, leaf.value_str);
3947 return ret;
3948}
3949
3950/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003951 * @brief Resolve instance-identifier predicate in JSON data format.
3952 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003953 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02003954 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02003955 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003956 * @param[in,out] node Node matching the restriction without
3957 * the predicate. If it does not satisfy the predicate,
3958 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003959 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003960 * @return Number of characters successfully parsed,
3961 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003962 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003963static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003964resolve_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 +02003965{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003966 /* ... /node[key=value] ... */
3967 struct lyd_node_leaf_list *key;
3968 struct lys_node_leaf **list_keys = NULL;
Michal Vaskoab8adcd2017-10-02 13:32:24 +02003969 struct lys_node_list *slist = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003970 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003971 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vasko53b7da02018-02-13 15:28:42 +01003972 struct ly_ctx *ctx = prev_mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003974 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02003975
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003976 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003977 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003978 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
3979 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003980 }
3981 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003982
Michal Vasko88850b72017-10-02 13:13:21 +02003983 if (!(*node)) {
3984 /* just parse it all */
3985 continue;
3986 }
3987
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003988 /* target */
3989 if (name[0] == '.') {
3990 /* leaf-list value */
3991 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003992 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02003993 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
3994 parsed = -1;
3995 goto cleanup;
3996 }
3997
3998 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02003999 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004000 *node = NULL;
4001 goto cleanup;
4002 }
4003
4004 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004005 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004006
4007 /* keyless list position */
4008 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004009 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004010 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4011 parsed = -1;
4012 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004013 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004014
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004015 if (((struct lys_node_list *)(*node)->schema)->keys) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004016 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list without keys, but have list \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004017 (*node)->schema->name);
4018 parsed = -1;
4019 goto cleanup;
4020 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004021
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004022 /* check the index */
4023 if (atoi(name) != cur_idx) {
4024 *node = NULL;
4025 goto cleanup;
4026 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004027
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004028 } else {
4029 /* list key value */
4030 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004031 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004032 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4033 parsed = -1;
4034 goto cleanup;
4035 }
4036 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004037
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004038 /* prepare key array */
4039 if (!list_keys) {
4040 list_keys = malloc(slist->keys_size * sizeof *list_keys);
Michal Vasko53b7da02018-02-13 15:28:42 +01004041 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004042 for (i = 0; i < slist->keys_size; ++i) {
4043 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02004044 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004045 }
4046
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004047 /* find the schema key leaf */
4048 for (i = 0; i < slist->keys_size; ++i) {
4049 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4050 break;
4051 }
4052 }
4053 if (i == slist->keys_size) {
4054 /* this list has no such key */
Michal Vasko53b7da02018-02-13 15:28:42 +01004055 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004056 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4057 parsed = -1;
4058 goto cleanup;
4059 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004060
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004061 /* check module */
4062 if (model) {
4063 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004064 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%.*s\", not \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004065 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4066 parsed = -1;
4067 goto cleanup;
4068 }
4069 } else {
4070 if (list_keys[i]->module != prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004071 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects key \"%s\" from module \"%s\", not \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004072 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4073 parsed = -1;
4074 goto cleanup;
4075 }
4076 }
4077
4078 /* find the actual data key */
4079 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4080 if (key->schema == (struct lys_node *)list_keys[i]) {
4081 break;
4082 }
4083 }
4084 if (!key) {
4085 /* list instance is missing a key? definitely should not happen */
Michal Vasko53b7da02018-02-13 15:28:42 +01004086 LOGINT(ctx);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004087 parsed = -1;
4088 goto cleanup;
4089 }
4090
4091 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004092 if (!valequal(key->schema, value, val_len, key->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004093 *node = NULL;
Michal Vasko88850b72017-10-02 13:13:21 +02004094 /* we still want to parse the whole predicate */
4095 continue;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004096 }
4097
4098 /* everything is fine, mark this key as resolved */
4099 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004100 }
4101 } while (has_predicate);
4102
Michal Vaskob2f40be2016-09-08 16:03:48 +02004103 /* check that all list keys were specified */
Michal Vasko88850b72017-10-02 13:13:21 +02004104 if (*node && list_keys) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004105 for (i = 0; i < slist->keys_size; ++i) {
4106 if (list_keys[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004107 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list key \"%s\".", list_keys[i]->name);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004108 parsed = -1;
4109 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004110 }
4111 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004112 }
4113
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004114cleanup:
4115 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004116 return parsed;
4117}
4118
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004119int
Michal Vaskof96dfb62017-08-17 12:23:49 +02004120lys_check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004121{
Michal Vasko0b963112017-08-11 12:45:36 +02004122 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004123 struct lyxp_set set;
Michal Vasko769f8032017-01-24 13:11:55 +01004124 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004125
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004126 if (check_place) {
4127 parent = node;
4128 while (parent) {
4129 if (parent->nodetype == LYS_GROUPING) {
4130 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004131 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004132 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004133 if (parent->nodetype == LYS_AUGMENT) {
4134 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004135 /* unresolved augment, skip for now (will be checked later) */
4136 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004137 } else {
4138 parent = ((struct lys_node_augment *)parent)->target;
4139 continue;
4140 }
4141 }
4142 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004143 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004144 }
4145
Michal Vaskof96dfb62017-08-17 12:23:49 +02004146 ret = lyxp_node_atomize(node, &set, 1);
Michal Vasko769f8032017-01-24 13:11:55 +01004147 if (ret == -1) {
4148 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004149 }
4150
Michal Vasko9e635ac2016-10-17 11:44:09 +02004151 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004152 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004153}
4154
Radek Krejcif71f48f2016-10-25 16:37:24 +02004155static int
4156check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4157{
Radek Krejcidce5f972017-09-12 15:47:49 +02004158 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004159
4160 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004161 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4162 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004163 LOGVAL(leaf->module->ctx, 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 +02004164 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4165 return -1;
4166 }
4167 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4168 * of leafref resolving (lys_leaf_add_leafref_target()) */
4169 } else if (type->base == LY_TYPE_UNION) {
4170 for (i = 0; i < type->info.uni.count; i++) {
4171 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4172 return -1;
4173 }
4174 }
4175 }
4176 return 0;
4177}
4178
Michal Vasko9e635ac2016-10-17 11:44:09 +02004179/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004180 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004181 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004182 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004183 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004184 * @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 +02004185 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004186 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004187 *
4188 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004189 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004190int
4191inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004192{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004193 struct lys_node_leaf *leaf;
Michal Vasko53b7da02018-02-13 15:28:42 +01004194 struct ly_ctx *ctx;
4195
4196 if (!node) {
4197 return 0;
4198 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004199
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004200 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Michal Vasko53b7da02018-02-13 15:28:42 +01004201 ctx = node->module->ctx;
4202
Radek Krejci1d82ef62015-08-07 14:44:40 +02004203 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004204 if (clear) {
4205 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004206 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004207 } else {
4208 if (node->flags & LYS_CONFIG_SET) {
4209 /* skip nodes with an explicit config value */
4210 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004211 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4212 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004213 return -1;
4214 }
4215 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004216 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004217
4218 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4219 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4220 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004221 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4222 && !((struct lys_node_list *)node)->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004223 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
Michal Vaskoe022a562016-09-27 14:24:15 +02004224 return -1;
4225 }
4226 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004227 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004228 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004229 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004230 return -1;
4231 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004232 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4233 leaf = (struct lys_node_leaf *)node;
4234 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004235 return -1;
4236 }
4237 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004238 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004239
4240 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004241}
4242
Michal Vasko730dfdf2015-08-11 14:48:05 +02004243/**
Michal Vasko7178e692016-02-12 15:58:05 +01004244 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004245 *
Michal Vaskobb211122015-08-19 14:03:11 +02004246 * @param[in] aug Augment to use.
Michal Vasko97234262018-02-01 09:53:01 +01004247 * @param[in] uses Parent where to start the search in. If set, uses augment, if not, standalone augment.
Radek Krejcib3142312016-11-09 11:04:12 +01004248 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004249 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004250 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004251 */
Michal Vasko7178e692016-02-12 15:58:05 +01004252static int
Michal Vasko97234262018-02-01 09:53:01 +01004253resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004254{
Michal Vasko44ab1462017-05-18 13:18:36 +02004255 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004256 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004257 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004258 struct ly_set *set;
Michal Vasko53b7da02018-02-13 15:28:42 +01004259 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004260
Michal Vasko2ef7db62017-06-12 09:24:02 +02004261 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004262 mod = lys_main_module(aug->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01004263 ctx = mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004264
Michal Vaskobb520442017-05-23 10:55:18 +02004265 /* set it as not applied for now */
4266 aug->flags |= LYS_NOTAPPLIED;
4267
Michal Vasko2ef7db62017-06-12 09:24:02 +02004268 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004269 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004270 /* resolve target node */
Michal Vasko97234262018-02-01 09:53:01 +01004271 rc = resolve_schema_nodeid(aug->target_name, uses, (uses ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004272 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004273 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004274 return -1;
4275 }
Michal Vasko50576712017-07-28 12:28:33 +02004276 if (!set) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004277 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004278 return EXIT_FAILURE;
4279 }
Michal Vasko50576712017-07-28 12:28:33 +02004280 aug->target = set->set.s[0];
4281 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004282 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004283
Michal Vaskod58d5962016-03-02 14:29:41 +01004284 /* check for mandatory nodes - if the target node is in another module
4285 * the added nodes cannot be mandatory
4286 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004287 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4288 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004289 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004290 }
4291
Michal Vasko07e89ef2016-03-03 13:28:57 +01004292 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004293 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004294 LY_TREE_FOR(aug->child, sub) {
4295 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4296 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004297 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4298 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004299 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004300 return -1;
4301 }
4302 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004303 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004304 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004305 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004306 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4307 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004308 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004309 return -1;
4310 }
4311 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004312 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004313 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004314 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004315 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4316 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004317 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004318 return -1;
4319 }
4320 }
4321 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004322 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4323 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004324 return -1;
4325 }
4326
Radek Krejcic071c542016-01-27 14:57:51 +01004327 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004328 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004329 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004330 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004331 }
4332 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004333
Michal Vasko44ab1462017-05-18 13:18:36 +02004334 if (!aug->child) {
4335 /* empty augment, nothing to connect, but it is techincally applied */
Michal Vasko53b7da02018-02-13 15:28:42 +01004336 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
Michal Vasko44ab1462017-05-18 13:18:36 +02004337 aug->flags &= ~LYS_NOTAPPLIED;
Radek Krejciaa6b2a12017-10-26 15:52:39 +02004338 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4339 /* we try to connect the augment only in case the module is implemented or
4340 * the augment applies on the used grouping, anyway we failed here */
Michal Vasko44ab1462017-05-18 13:18:36 +02004341 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004342 }
4343
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004344 return EXIT_SUCCESS;
4345}
4346
Radek Krejcie534c132016-11-23 13:32:31 +01004347static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004348resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004349{
4350 enum LY_VLOG_ELEM vlog_type;
4351 void *vlog_node;
4352 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004353 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004354 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004355 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004356 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004357 struct lys_ext_instance *tmp_ext;
Michal Vasko53b7da02018-02-13 15:28:42 +01004358 struct ly_ctx *ctx = NULL;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004359 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004360
4361 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004362 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004363 vlog_node = info->parent;
4364 vlog_type = LY_VLOG_LYS;
4365 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004366 case LYEXT_PAR_MODULE:
4367 case LYEXT_PAR_IMPORT:
4368 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004369 vlog_node = NULL;
4370 vlog_type = LY_VLOG_LYS;
4371 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004372 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004373 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004374 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004375 break;
4376 }
4377
4378 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004379 /* YIN */
4380
Radek Krejcie534c132016-11-23 13:32:31 +01004381 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004382 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004383 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004384 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004385 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004386 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004387 ctx = mod->ctx;
Radek Krejcie534c132016-11-23 13:32:31 +01004388
4389 /* find the extension definition */
4390 e = NULL;
4391 for (i = 0; i < mod->extensions_size; i++) {
4392 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4393 e = &mod->extensions[i];
4394 break;
4395 }
4396 }
4397 /* try submodules */
4398 for (j = 0; !e && j < mod->inc_size; j++) {
4399 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4400 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4401 e = &mod->inc[j].submodule->extensions[i];
4402 break;
4403 }
4404 }
4405 }
4406 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004407 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004408 return EXIT_FAILURE;
4409 }
4410
4411 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004412
Radek Krejci72b35992017-01-04 16:27:44 +01004413 if (e->plugin && e->plugin->check_position) {
4414 /* common part - we have plugin with position checking function, use it first */
4415 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4416 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004417 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004418 return -1;
4419 }
4420 }
4421
Radek Krejci8d6b7422017-02-03 14:42:13 +01004422 /* extension type-specific part - allocation */
4423 if (e->plugin) {
4424 etype = e->plugin->type;
4425 } else {
4426 /* default type */
4427 etype = LYEXT_FLAG;
4428 }
4429 switch (etype) {
4430 case LYEXT_FLAG:
4431 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4432 break;
4433 case LYEXT_COMPLEX:
4434 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4435 break;
4436 case LYEXT_ERR:
4437 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004438 LOGINT(ctx);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004439 return -1;
4440 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004441 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004442
4443 /* common part for all extension types */
4444 (*ext)->def = e;
4445 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004446 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004447 (*ext)->insubstmt = info->substmt;
4448 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004449 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004450
4451 if (!(e->flags & LYS_YINELEM) && e->argument) {
4452 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4453 if (!(*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004454 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004455 return -1;
4456 }
4457 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4458 }
4459
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004460 (*ext)->nodetype = LYS_EXT;
4461 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004462
Radek Krejci8d6b7422017-02-03 14:42:13 +01004463 /* extension type-specific part - parsing content */
4464 switch (etype) {
4465 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004466 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4467 if (!yin->ns) {
4468 /* garbage */
4469 lyxml_free(mod->ctx, yin);
4470 continue;
4471 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4472 /* standard YANG statements are not expected here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004473 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004474 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004475 } else if (yin->ns == info->data.yin->ns &&
4476 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004477 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004478 if ((*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004479 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004480 return -1;
4481 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004482 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004483 yin->content = NULL;
4484 lyxml_free(mod->ctx, yin);
4485 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004486 /* extension instance */
4487 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4488 LYEXT_SUBSTMT_SELF, 0, unres)) {
4489 return -1;
4490 }
Radek Krejci72b35992017-01-04 16:27:44 +01004491
Radek Krejci72b35992017-01-04 16:27:44 +01004492 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004493 }
Radek Krejci72b35992017-01-04 16:27:44 +01004494 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004495 break;
4496 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004497 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004498 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4499 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004500 return -1;
4501 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004502 break;
4503 default:
4504 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004505 }
Radek Krejci72b35992017-01-04 16:27:44 +01004506
4507 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4508
Radek Krejcie534c132016-11-23 13:32:31 +01004509 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004510 /* YANG */
4511
PavolVicanc1807262017-01-31 18:00:27 +01004512 ext_prefix = (char *)(*ext)->def;
4513 tmp = strchr(ext_prefix, ':');
4514 if (!tmp) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004515 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004516 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004517 }
4518 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004519
PavolVicanc1807262017-01-31 18:00:27 +01004520 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004521 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
PavolVicanc1807262017-01-31 18:00:27 +01004522 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004523 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004524 return EXIT_FAILURE;
4525 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004526 ctx = mod->ctx;
PavolVicanc1807262017-01-31 18:00:27 +01004527
4528 /* find the extension definition */
4529 e = NULL;
4530 for (i = 0; i < mod->extensions_size; i++) {
4531 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4532 e = &mod->extensions[i];
4533 break;
4534 }
4535 }
4536 /* try submodules */
4537 for (j = 0; !e && j < mod->inc_size; j++) {
4538 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4539 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4540 e = &mod->inc[j].submodule->extensions[i];
4541 break;
4542 }
4543 }
4544 }
4545 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004546 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004547 return EXIT_FAILURE;
4548 }
4549
4550 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4551
4552 if (e->plugin && e->plugin->check_position) {
4553 /* common part - we have plugin with position checking function, use it first */
4554 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4555 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004556 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004557 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004558 }
4559 }
4560
PavolVican22e88682017-02-14 22:38:18 +01004561 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004562 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004563 (*ext)->def = e;
4564 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004565 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004566
PavolVicanb0d84102017-02-15 16:32:42 +01004567 if (e->argument && !(*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004568 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
PavolVicanb0d84102017-02-15 16:32:42 +01004569 goto error;
4570 }
4571
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004572 (*ext)->module = info->mod;
4573 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004574
PavolVican22e88682017-02-14 22:38:18 +01004575 /* extension type-specific part */
4576 if (e->plugin) {
4577 etype = e->plugin->type;
4578 } else {
4579 /* default type */
4580 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004581 }
PavolVican22e88682017-02-14 22:38:18 +01004582 switch (etype) {
4583 case LYEXT_FLAG:
4584 /* nothing change */
4585 break;
4586 case LYEXT_COMPLEX:
4587 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Michal Vasko53b7da02018-02-13 15:28:42 +01004588 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
PavolVican22e88682017-02-14 22:38:18 +01004589 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4590 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004591 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004592 if (info->data.yang) {
4593 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004594 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4595 (struct lys_ext_instance_complex*)(*ext))) {
4596 goto error;
4597 }
4598 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4599 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004600 goto error;
4601 }
PavolVicana3876672017-02-21 15:49:51 +01004602 }
4603 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4604 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004605 }
PavolVican22e88682017-02-14 22:38:18 +01004606 break;
4607 case LYEXT_ERR:
4608 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004609 LOGINT(ctx);
PavolVican22e88682017-02-14 22:38:18 +01004610 goto error;
4611 }
4612
PavolVican22e88682017-02-14 22:38:18 +01004613 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4614 goto error;
4615 }
4616 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004617 }
4618
4619 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004620error:
4621 free(ext_prefix);
4622 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004623}
4624
Michal Vasko730dfdf2015-08-11 14:48:05 +02004625/**
Pavol Vican855ca622016-09-05 13:07:54 +02004626 * @brief Resolve (find) choice default case. Does not log.
4627 *
4628 * @param[in] choic Choice to use.
4629 * @param[in] dflt Name of the default case.
4630 *
4631 * @return Pointer to the default node or NULL.
4632 */
4633static struct lys_node *
4634resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4635{
4636 struct lys_node *child, *ret;
4637
4638 LY_TREE_FOR(choic->child, child) {
4639 if (child->nodetype == LYS_USES) {
4640 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4641 if (ret) {
4642 return ret;
4643 }
4644 }
4645
4646 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004647 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004648 return child;
4649 }
4650 }
4651
4652 return NULL;
4653}
4654
4655/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004656 * @brief Resolve uses, apply augments, refines. Logs directly.
4657 *
Michal Vaskobb211122015-08-19 14:03:11 +02004658 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004659 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004660 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004661 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004662 */
Michal Vasko184521f2015-09-24 13:14:26 +02004663static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004664resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004665{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004666 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004667 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004668 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004669 struct lys_node_leaflist *llist;
4670 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004671 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004672 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004673 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004674 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004675 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004676 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004677
Michal Vasko71e1aa82015-08-12 12:17:51 +02004678 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004679
Radek Krejci93def382017-05-24 15:33:48 +02004680 /* check that the grouping is resolved (no unresolved uses inside) */
4681 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004682
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004683 if (!uses->grp->child) {
4684 /* grouping without children, warning was already displayed */
4685 return EXIT_SUCCESS;
4686 }
4687
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004688 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004689 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004690 if (node_aux->nodetype & LYS_GROUPING) {
4691 /* do not instantiate groupings from groupings */
4692 continue;
4693 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004694 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004695 if (!node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004696 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4697 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004698 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004699 }
Pavol Vican55abd332016-07-12 15:54:49 +02004700 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004701 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 +02004702 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004703 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004704 }
4705 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004706 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004707
Michal Vaskodef0db12015-10-07 13:22:48 +02004708 /* we managed to copy the grouping, the rest must be possible to resolve */
4709
Pavol Vican855ca622016-09-05 13:07:54 +02004710 if (uses->refine_size) {
4711 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Michal Vasko53b7da02018-02-13 15:28:42 +01004712 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004713 }
4714
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004715 /* apply refines */
4716 for (i = 0; i < uses->refine_size; i++) {
4717 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004718 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4719 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004720 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004721 if (rc || !node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004722 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004723 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004724 }
4725
Radek Krejci1d82ef62015-08-07 14:44:40 +02004726 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004727 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4728 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004729 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004730 }
Pavol Vican855ca622016-09-05 13:07:54 +02004731 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004732
4733 /* description on any nodetype */
4734 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004735 lydict_remove(ctx, node->dsc);
4736 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004737 }
4738
4739 /* reference on any nodetype */
4740 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004741 lydict_remove(ctx, node->ref);
4742 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004743 }
4744
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004745 /* config on any nodetype,
4746 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4747 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004748 node->flags &= ~LYS_CONFIG_MASK;
4749 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004750 }
4751
4752 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004753 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004754 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004755 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004756 leaf = (struct lys_node_leaf *)node;
4757
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004758 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004759 lydict_remove(ctx, leaf->dflt);
4760 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4761
4762 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004763 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4764 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004765 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004766 }
Radek Krejci200bf712016-08-16 17:11:04 +02004767 } else if (node->nodetype == LYS_LEAFLIST) {
4768 /* leaf-list */
4769 llist = (struct lys_node_leaflist *)node;
4770
4771 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004772 for (j = 0; j < llist->dflt_size; j++) {
4773 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004774 }
4775 free(llist->dflt);
4776
4777 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02004778 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
Michal Vasko53b7da02018-02-13 15:28:42 +01004779 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004780 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004781 for (j = 0; j < llist->dflt_size; j++) {
4782 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004783 }
4784
4785 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004786 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004787 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004788 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004789 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004790 }
4791 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004792 }
4793 }
4794
4795 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004796 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004797 /* remove current value */
4798 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004799
Radek Krejcibf285832017-01-26 16:05:41 +01004800 /* set new value */
4801 node->flags |= (rfn->flags & LYS_MAND_MASK);
4802
Pavol Vican855ca622016-09-05 13:07:54 +02004803 if (rfn->flags & LYS_MAND_TRUE) {
4804 /* check if node has default value */
4805 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004806 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02004807 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004808 goto fail;
4809 }
4810 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004811 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02004812 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004813 goto fail;
4814 }
4815 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004816 }
4817
4818 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004819 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4820 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4821 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004822 }
4823
4824 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004825 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004826 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004827 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004829 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004830 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004831 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004832 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004833 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004834 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004835 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004836 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004837 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004838 }
4839 }
4840
4841 /* must in leaf, leaf-list, list, container or anyxml */
4842 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004843 switch (node->nodetype) {
4844 case LYS_LEAF:
4845 old_size = &((struct lys_node_leaf *)node)->must_size;
4846 old_must = &((struct lys_node_leaf *)node)->must;
4847 break;
4848 case LYS_LEAFLIST:
4849 old_size = &((struct lys_node_leaflist *)node)->must_size;
4850 old_must = &((struct lys_node_leaflist *)node)->must;
4851 break;
4852 case LYS_LIST:
4853 old_size = &((struct lys_node_list *)node)->must_size;
4854 old_must = &((struct lys_node_list *)node)->must;
4855 break;
4856 case LYS_CONTAINER:
4857 old_size = &((struct lys_node_container *)node)->must_size;
4858 old_must = &((struct lys_node_container *)node)->must;
4859 break;
4860 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004861 case LYS_ANYDATA:
4862 old_size = &((struct lys_node_anydata *)node)->must_size;
4863 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004864 break;
4865 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01004866 LOGINT(ctx);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004867 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004868 }
4869
4870 size = *old_size + rfn->must_size;
4871 must = realloc(*old_must, size * sizeof *rfn->must);
Michal Vasko53b7da02018-02-13 15:28:42 +01004872 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004873 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004874 must[j].ext_size = rfn->must[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01004875 lys_ext_dup(ctx, rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejci5138e9f2017-04-12 13:10:46 +02004876 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004877 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4878 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4879 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4880 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4881 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02004882 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004883 }
4884
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004885 *old_must = must;
4886 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004887
4888 /* check XPath dependencies again */
4889 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4890 goto fail;
4891 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004892 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004893
4894 /* if-feature in leaf, leaf-list, list, container or anyxml */
4895 if (rfn->iffeature_size) {
4896 old_size = &node->iffeature_size;
4897 old_iff = &node->iffeature;
4898
4899 size = *old_size + rfn->iffeature_size;
4900 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Michal Vasko53b7da02018-02-13 15:28:42 +01004901 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02004902 *old_iff = iff;
4903
Pavol Vican855ca622016-09-05 13:07:54 +02004904 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4905 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004906 if (usize1) {
4907 /* there is something to duplicate */
4908 /* duplicate compiled expression */
4909 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4910 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Michal Vasko53b7da02018-02-13 15:28:42 +01004911 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004912 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004913
4914 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004915 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Michal Vasko53b7da02018-02-13 15:28:42 +01004916 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004917 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004918
Radek Krejci3a3b2002017-09-13 16:39:02 +02004919 /* duplicate extensions */
4920 iff[j].ext_size = rfn->iffeature[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01004921 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
Radek Krejci3a3b2002017-09-13 16:39:02 +02004922 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
4923 }
4924 (*old_size)++;
4925 }
4926 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004927 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004928 }
4929
4930 /* apply augments */
4931 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko97234262018-02-01 09:53:01 +01004932 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004933 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004934 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004935 }
4936 }
4937
Pavol Vican855ca622016-09-05 13:07:54 +02004938 /* check refines */
4939 for (i = 0; i < uses->refine_size; i++) {
4940 node = refine_nodes[i];
4941 rfn = &uses->refine[i];
4942
4943 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004944 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004945 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004946 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004947 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4948 (rfn->flags & LYS_CONFIG_W)) {
4949 /* setting config true under config false is prohibited */
Michal Vasko53b7da02018-02-13 15:28:42 +01004950 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4951 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004952 "changing config from 'false' to 'true' is prohibited while "
4953 "the target's parent is still config 'false'.");
4954 goto fail;
4955 }
4956
4957 /* inherit config change to the target children */
4958 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4959 if (rfn->flags & LYS_CONFIG_W) {
4960 if (iter->flags & LYS_CONFIG_SET) {
4961 /* config is set explicitely, go to next sibling */
4962 next = NULL;
4963 goto nextsibling;
4964 }
4965 } else { /* LYS_CONFIG_R */
4966 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4967 /* error - we would have config data under status data */
Michal Vasko53b7da02018-02-13 15:28:42 +01004968 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4969 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004970 "changing config from 'true' to 'false' is prohibited while the target "
4971 "has still a children with explicit config 'true'.");
4972 goto fail;
4973 }
4974 }
4975 /* change config */
4976 iter->flags &= ~LYS_CONFIG_MASK;
4977 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4978
4979 /* select next iter - modified LY_TREE_DFS_END */
4980 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4981 next = NULL;
4982 } else {
4983 next = iter->child;
4984 }
4985nextsibling:
4986 if (!next) {
4987 /* try siblings */
4988 next = iter->next;
4989 }
4990 while (!next) {
4991 /* parent is already processed, go to its sibling */
4992 iter = lys_parent(iter);
4993
4994 /* no siblings, go back through parents */
4995 if (iter == node) {
4996 /* we are done, no next element to process */
4997 break;
4998 }
4999 next = iter->next;
5000 }
5001 }
5002 }
5003
5004 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005005 if (rfn->dflt_size) {
5006 if (node->nodetype == LYS_CHOICE) {
5007 /* choice */
5008 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5009 rfn->dflt[0]);
5010 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005011 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005012 goto fail;
5013 }
5014 if (lyp_check_mandatory_choice(node)) {
5015 goto fail;
5016 }
Pavol Vican855ca622016-09-05 13:07:54 +02005017 }
5018 }
5019
5020 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005021 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005022 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005023 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5024 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005025 goto fail;
5026 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005027 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005028 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005029 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5030 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005031 goto fail;
5032 }
5033 }
5034
5035 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005036 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005037 if (node->nodetype == LYS_LEAFLIST) {
5038 llist = (struct lys_node_leaflist *)node;
5039 if (llist->dflt_size && llist->min) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005040 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5041 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005042 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5043 goto fail;
5044 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005045 } else if (node->nodetype == LYS_LEAF) {
5046 leaf = (struct lys_node_leaf *)node;
5047 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005048 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5049 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005050 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5051 goto fail;
5052 }
Pavol Vican855ca622016-09-05 13:07:54 +02005053 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005054
Pavol Vican855ca622016-09-05 13:07:54 +02005055 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005056 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005057 for (parent = node->parent;
5058 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5059 parent = parent->parent) {
5060 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5061 /* stop also on presence containers */
5062 break;
5063 }
5064 }
5065 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5066 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5067 if (lyp_check_mandatory_choice(parent)) {
5068 goto fail;
5069 }
5070 }
5071 }
5072 }
5073 free(refine_nodes);
5074
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005075 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005076
5077fail:
5078 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5079 lys_node_free(iter, NULL, 0);
5080 }
Pavol Vican855ca622016-09-05 13:07:54 +02005081 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005082 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005083}
5084
Radek Krejci83a4bac2017-02-07 15:53:04 +01005085void
5086resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005087{
5088 int i;
5089
5090 assert(der && base);
5091
Radek Krejci018f1f52016-08-03 16:01:20 +02005092 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005093 /* create a set for backlinks if it does not exist */
5094 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005095 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005096 /* store backlink */
5097 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005098
Radek Krejci85a54be2016-10-20 12:39:56 +02005099 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005100 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005101 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005102 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005103}
5104
Michal Vasko730dfdf2015-08-11 14:48:05 +02005105/**
5106 * @brief Resolve base identity recursively. Does not log.
5107 *
5108 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005109 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005110 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005111 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005112 *
Radek Krejci219fa612016-08-15 10:36:51 +02005113 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005114 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005115static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005116resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005117 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005118{
Michal Vaskof02e3742015-08-05 16:27:02 +02005119 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005120 struct lys_ident *base = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005121 struct ly_ctx *ctx = module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005122
Radek Krejcicf509982015-12-15 09:22:44 +01005123 assert(ret);
5124
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005125 /* search module */
5126 for (i = 0; i < module->ident_size; i++) {
5127 if (!strcmp(basename, module->ident[i].name)) {
5128
5129 if (!ident) {
5130 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005131 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005132 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005133 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005134 }
5135
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005136 base = &module->ident[i];
5137 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005138 }
5139 }
5140
5141 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005142 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5143 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5144 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005145
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005146 if (!ident) {
5147 *ret = &module->inc[j].submodule->ident[i];
5148 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005149 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005150
5151 base = &module->inc[j].submodule->ident[i];
5152 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005153 }
5154 }
5155 }
5156
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005157matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005158 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005159 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005160 /* is it already completely resolved? */
5161 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005162 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005163 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5164
5165 /* simple check for circular reference,
5166 * the complete check is done as a side effect of using only completely
5167 * resolved identities (previous check of unres content) */
5168 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005169 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5170 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005171 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005172 }
5173
Radek Krejci06f64ed2016-08-15 11:07:44 +02005174 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005175 }
5176 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005177
Radek Krejcibabbff82016-02-19 13:31:37 +01005178 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005179 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005180 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005181 }
5182
Radek Krejci219fa612016-08-15 10:36:51 +02005183 /* base not found (maybe a forward reference) */
5184 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005185}
5186
Michal Vasko730dfdf2015-08-11 14:48:05 +02005187/**
5188 * @brief Resolve base identity. Logs directly.
5189 *
5190 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005191 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005192 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005193 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005194 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005195 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005196 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005197 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005198static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005199resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005200 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005201{
5202 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005203 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005204 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005205 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005206 struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005207 struct ly_ctx *ctx = module->ctx;
Radek Krejcicf509982015-12-15 09:22:44 +01005208
5209 assert((ident && !type) || (!ident && type));
5210
5211 if (!type) {
5212 /* have ident to resolve */
5213 ret = &target;
5214 flags = ident->flags;
5215 mod = ident->module;
5216 } else {
5217 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005218 ++type->info.ident.count;
5219 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
Michal Vasko53b7da02018-02-13 15:28:42 +01005220 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005221
5222 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005223 flags = type->parent->flags;
5224 mod = type->parent->module;
5225 }
Michal Vaskof2006002016-04-21 16:28:15 +02005226 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005227
5228 /* search for the base identity */
5229 name = strchr(basename, ':');
5230 if (name) {
5231 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005232 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005233 name++;
5234
Michal Vasko2d851a92015-10-20 16:16:36 +02005235 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005236 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005237 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005238 }
5239 } else {
5240 name = basename;
5241 }
5242
Radek Krejcic071c542016-01-27 14:57:51 +01005243 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005244 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
Radek Krejcic071c542016-01-27 14:57:51 +01005245 if (!module) {
5246 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01005247 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005248 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005249 }
5250
Radek Krejcic071c542016-01-27 14:57:51 +01005251 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005252 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5253 if (!rc) {
5254 assert(*ret);
5255
5256 /* check status */
5257 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5258 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5259 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005260 } else if (ident) {
5261 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005262 if (lys_main_module(mod)->implemented) {
5263 /* in case of the implemented identity, maintain backlinks to it
5264 * from the base identities to make it available when resolving
5265 * data with the identity values (not implemented identity is not
5266 * allowed as an identityref value). */
5267 resolve_identity_backlink_update(ident, *ret);
5268 }
Radek Krejci219fa612016-08-15 10:36:51 +02005269 }
5270 } else if (rc == EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005271 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005272 if (type) {
5273 --type->info.ident.count;
5274 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005275 }
5276
Radek Krejci219fa612016-08-15 10:36:51 +02005277 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005278}
5279
Radek Krejci9e6af732017-04-27 14:40:25 +02005280/*
5281 * 1 - true (der is derived from base)
5282 * 0 - false (der is not derived from base)
5283 */
5284static int
5285search_base_identity(struct lys_ident *der, struct lys_ident *base)
5286{
5287 int i;
5288
5289 if (der == base) {
5290 return 1;
5291 } else {
5292 for(i = 0; i < der->base_size; i++) {
5293 if (search_base_identity(der->base[i], base) == 1) {
5294 return 1;
5295 }
5296 }
5297 }
5298
5299 return 0;
5300}
5301
Michal Vasko730dfdf2015-08-11 14:48:05 +02005302/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005303 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005304 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005305 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005306 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005307 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005308 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005309 *
5310 * @return Pointer to the identity resolvent, NULL on error.
5311 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005312struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005313resolve_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 +02005314{
Radek Krejci9e6af732017-04-27 14:40:25 +02005315 const char *mod_name, *name;
Michal Vasko08767f72017-10-06 14:38:08 +02005316 char *str;
Radek Krejcidce5f972017-09-12 15:47:49 +02005317 int mod_name_len, nam_len, rc;
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005318 int need_implemented = 0;
Michal Vasko08767f72017-10-06 14:38:08 +02005319 unsigned int i, j;
Michal Vaskof2d43962016-09-02 11:10:16 +02005320 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005321 struct lys_module *imod = NULL, *m;
Michal Vasko53b7da02018-02-13 15:28:42 +01005322 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005323
Radek Krejci9e6af732017-04-27 14:40:25 +02005324 assert(type && ident_name && node && mod);
Michal Vasko53b7da02018-02-13 15:28:42 +01005325 ctx = mod->ctx;
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005326
Michal Vaskof2d43962016-09-02 11:10:16 +02005327 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005328 return NULL;
5329 }
5330
Michal Vasko50576712017-07-28 12:28:33 +02005331 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005332 if (rc < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005333 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005334 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005335 } else if (rc < (signed)strlen(ident_name)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005336 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005337 return NULL;
5338 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005339
5340 m = lys_main_module(mod); /* shortcut */
5341 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5342 /* identity is defined in the same module as node */
5343 imod = m;
5344 } else if (dflt) {
5345 /* solving identityref in default definition in schema -
5346 * find the identity's module in the imported modules list to have a correct revision */
5347 for (i = 0; i < mod->imp_size; i++) {
5348 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5349 imod = mod->imp[i].module;
5350 break;
5351 }
5352 }
5353 } else {
Michal Vasko08767f72017-10-06 14:38:08 +02005354 /* solving identityref in data - get the module from the context */
5355 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5356 imod = mod->ctx->models.list[i];
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005357 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
Radek Krejci9e6af732017-04-27 14:40:25 +02005358 break;
5359 }
Michal Vasko08767f72017-10-06 14:38:08 +02005360 imod = NULL;
5361 }
Radek Krejci5ba05102017-10-26 15:02:52 +02005362 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5363 /* we are currently parsing some module and checking XPath or a default value,
5364 * so take this module into account */
5365 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5366 imod = mod->ctx->models.parsing_sub_modules[i];
5367 if (imod->type) {
5368 /* skip submodules */
5369 continue;
5370 }
5371 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5372 break;
5373 }
5374 imod = NULL;
5375 }
5376 }
Michal Vasko08767f72017-10-06 14:38:08 +02005377 }
5378
Michal Vasko53b7da02018-02-13 15:28:42 +01005379 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
Michal Vasko08767f72017-10-06 14:38:08 +02005380 /* the needed module was not found, but it may have been expected so call the data callback */
5381 if (imod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005382 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci58523dc2017-10-27 10:00:17 +02005383 } else if (mod_name) {
Michal Vasko08767f72017-10-06 14:38:08 +02005384 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01005385 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
Michal Vasko08767f72017-10-06 14:38:08 +02005386 free(str);
Radek Krejci9e6af732017-04-27 14:40:25 +02005387 }
5388 }
5389 if (!imod) {
5390 goto fail;
5391 }
5392
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005393 if (m != imod || lys_main_module(type->parent->module) != mod) {
Michal Vasko08767f72017-10-06 14:38:08 +02005394 /* the type is not referencing the same schema,
Radek Krejci9e6af732017-04-27 14:40:25 +02005395 * THEN, we may need to make the module with the identity implemented, but only if it really
5396 * contains the identity */
5397 if (!imod->implemented) {
5398 cur = NULL;
5399 /* get the identity in the module */
5400 for (i = 0; i < imod->ident_size; i++) {
5401 if (!strcmp(name, imod->ident[i].name)) {
5402 cur = &imod->ident[i];
5403 break;
5404 }
5405 }
5406 if (!cur) {
5407 /* go through includes */
5408 for (j = 0; j < imod->inc_size; j++) {
5409 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5410 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5411 cur = &imod->inc[j].submodule->ident[i];
5412 break;
5413 }
5414 }
5415 }
5416 if (!cur) {
5417 goto fail;
5418 }
5419 }
5420
5421 /* check that identity is derived from one of the type's base */
5422 while (type->der) {
5423 for (i = 0; i < type->info.ident.count; i++) {
5424 if (search_base_identity(cur, type->info.ident.ref[i])) {
5425 /* cur's base matches the type's base */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005426 need_implemented = 1;
Radek Krejci9e6af732017-04-27 14:40:25 +02005427 goto match;
5428 }
5429 }
5430 type = &type->der->type;
5431 }
5432 /* matching base not found */
Michal Vasko53b7da02018-02-13 15:28:42 +01005433 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Radek Krejci9e6af732017-04-27 14:40:25 +02005434 goto fail;
5435 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005436 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005437
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005438 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005439 while (type->der) {
5440 for (i = 0; i < type->info.ident.count; ++i) {
5441 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005442
Radek Krejci85a54be2016-10-20 12:39:56 +02005443 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005444 /* there are some derived identities */
Michal Vasko08767f72017-10-06 14:38:08 +02005445 for (j = 0; j < cur->der->number; j++) {
5446 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005447 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005448 /* we have match */
5449 cur = der;
5450 goto match;
5451 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005452 }
5453 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005454 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005455 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005456 }
5457
Radek Krejci9e6af732017-04-27 14:40:25 +02005458fail:
Michal Vasko53b7da02018-02-13 15:28:42 +01005459 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005460 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005461
5462match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005463 for (i = 0; i < cur->iffeature_size; i++) {
5464 if (!resolve_iffeature(&cur->iffeature[i])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005465 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5466 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005467 return NULL;
5468 }
5469 }
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005470 if (need_implemented) {
5471 if (dflt) {
5472 /* try to make the module implemented */
5473 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5474 imod->name, cur->name, mod->name);
5475 if (lys_set_implemented(imod)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005476 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005477 imod->name, cur->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01005478 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005479 goto fail;
5480 }
5481 } else {
5482 /* just say that it was found, but in a non-implemented module */
Michal Vasko53b7da02018-02-13 15:28:42 +01005483 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005484 lys_main_module(cur->module)->name);
Radek Krejci9e6af732017-04-27 14:40:25 +02005485 goto fail;
5486 }
5487 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005488 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005489}
5490
Michal Vasko730dfdf2015-08-11 14:48:05 +02005491/**
Michal Vaskobb211122015-08-19 14:03:11 +02005492 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005493 *
Michal Vaskobb211122015-08-19 14:03:11 +02005494 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005495 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005496 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005497 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005498 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005499static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005500resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005501{
Radek Krejci93def382017-05-24 15:33:48 +02005502 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005503 struct lys_node *par_grp;
Michal Vasko53b7da02018-02-13 15:28:42 +01005504 struct ly_ctx *ctx = uses->module->ctx;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005505
Radek Krejci6ff885d2017-01-03 14:06:22 +01005506 /* 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 +02005507 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5508 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5509 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005510 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 +02005511
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005512 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005513 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5514 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005515 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005516 return -1;
5517 } else if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005518 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005519 return -1;
5520 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005521 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005522 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005523 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005524 return -1;
5525 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005526 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005527 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005528 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005529 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005530 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005531 }
5532
Radek Krejci93def382017-05-24 15:33:48 +02005533 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005534 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005535 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005536 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005537 return -1;
5538 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005539 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005540 } else {
5541 /* instantiate grouping only when it is completely resolved */
5542 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005543 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005544 return EXIT_FAILURE;
5545 }
5546
Radek Krejci48464ed2016-03-17 15:44:09 +01005547 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005548 if (!rc) {
5549 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005550 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005551 assert(((struct lys_node_grp *)par_grp)->unres_count);
5552 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005553 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005554 }
Radek Krejcicf509982015-12-15 09:22:44 +01005555
5556 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005557 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005558 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005559 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005560 return -1;
5561 }
5562
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005563 return EXIT_SUCCESS;
5564 }
5565
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005566 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005567}
5568
Michal Vasko730dfdf2015-08-11 14:48:05 +02005569/**
Michal Vasko9957e592015-08-17 15:04:09 +02005570 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005571 *
Michal Vaskobb211122015-08-19 14:03:11 +02005572 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005573 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005574 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005575 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005576 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005577static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005578resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005579{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005580 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005581 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005582 char *s = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005583 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005584
5585 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005586 assert(keys_str);
5587
Radek Krejci5c08a992016-11-02 13:30:04 +01005588 if (!list->child) {
5589 /* no child, possible forward reference */
Michal Vasko53b7da02018-02-13 15:28:42 +01005590 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Radek Krejci5c08a992016-11-02 13:30:04 +01005591 return EXIT_FAILURE;
5592 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005593 /* get the key name */
5594 if ((value = strpbrk(keys_str, " \t\n"))) {
5595 len = value - keys_str;
5596 while (isspace(value[0])) {
5597 value++;
5598 }
5599 } else {
5600 len = strlen(keys_str);
5601 }
5602
Radek Krejcia98048c2017-05-24 16:35:48 +02005603 if (list->keys[i]) {
5604 /* skip already resolved keys */
5605 goto next;
5606 }
5607
Michal Vaskobb520442017-05-23 10:55:18 +02005608 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5609 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005610 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005611 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005612 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005613 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005614
Radek Krejci48464ed2016-03-17 15:44:09 +01005615 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005616 /* check_key logs */
5617 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005618 }
5619
Radek Krejcicf509982015-12-15 09:22:44 +01005620 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005621 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005622 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5623 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005624 return -1;
5625 }
5626
Radek Krejcia98048c2017-05-24 16:35:48 +02005627 /* default value - is ignored, keep it but print a warning */
5628 if (list->keys[i]->dflt) {
5629 /* log is not hidden only in case this resolving fails and in such a case
5630 * we cannot get here
5631 */
Michal Vasko53b7da02018-02-13 15:28:42 +01005632 assert(log_opt == ILO_STORE);
5633 log_opt = ILO_LOG;
5634 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
Michal Vasko395b0a02018-01-22 09:36:20 +01005635 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
Michal Vasko53b7da02018-02-13 15:28:42 +01005636 log_opt = ILO_STORE;
Radek Krejcia98048c2017-05-24 16:35:48 +02005637 free(s);
5638 }
5639
5640next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005641 /* prepare for next iteration */
5642 while (value && isspace(value[0])) {
5643 value++;
5644 }
5645 keys_str = value;
5646 }
5647
Michal Vaskof02e3742015-08-05 16:27:02 +02005648 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005649}
5650
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005651/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005652 * @brief Resolve (check) all must conditions of \p node.
5653 * Logs directly.
5654 *
5655 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005656 * @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 +02005657 *
5658 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5659 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005660static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005661resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005662{
Michal Vaskobf19d252015-10-08 15:39:17 +02005663 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005664 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005665 struct lys_restr *must;
5666 struct lyxp_set set;
Michal Vasko53b7da02018-02-13 15:28:42 +01005667 struct ly_ctx *ctx = node->schema->module->ctx;
Michal Vaskobf19d252015-10-08 15:39:17 +02005668
5669 assert(node);
5670 memset(&set, 0, sizeof set);
5671
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005672 if (inout_parent) {
5673 for (schema = lys_parent(node->schema);
5674 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5675 schema = lys_parent(schema));
5676 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005677 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005678 return -1;
5679 }
5680 must_size = ((struct lys_node_inout *)schema)->must_size;
5681 must = ((struct lys_node_inout *)schema)->must;
5682
5683 /* context node is the RPC/action */
5684 node = node->parent;
5685 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005686 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005687 return -1;
5688 }
5689 } else {
5690 switch (node->schema->nodetype) {
5691 case LYS_CONTAINER:
5692 must_size = ((struct lys_node_container *)node->schema)->must_size;
5693 must = ((struct lys_node_container *)node->schema)->must;
5694 break;
5695 case LYS_LEAF:
5696 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5697 must = ((struct lys_node_leaf *)node->schema)->must;
5698 break;
5699 case LYS_LEAFLIST:
5700 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5701 must = ((struct lys_node_leaflist *)node->schema)->must;
5702 break;
5703 case LYS_LIST:
5704 must_size = ((struct lys_node_list *)node->schema)->must_size;
5705 must = ((struct lys_node_list *)node->schema)->must;
5706 break;
5707 case LYS_ANYXML:
5708 case LYS_ANYDATA:
5709 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5710 must = ((struct lys_node_anydata *)node->schema)->must;
5711 break;
5712 case LYS_NOTIF:
5713 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5714 must = ((struct lys_node_notif *)node->schema)->must;
5715 break;
5716 default:
5717 must_size = 0;
5718 break;
5719 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005720 }
5721
5722 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005723 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005724 return -1;
5725 }
5726
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005727 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005728
Michal Vasko8146d4c2016-05-09 15:50:29 +02005729 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02005730 if ((ignore_fail == 1) || ((must[i].flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005731 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5732 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01005733 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005734 if (must[i].emsg) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005735 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005736 }
5737 if (must[i].eapptag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005738 ly_err_last_set_apptag(ctx, must[i].eapptag);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005739 }
5740 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005741 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005742 }
5743 }
5744
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005745 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005746}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005747
Michal Vaskobf19d252015-10-08 15:39:17 +02005748/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005749 * @brief Resolve (find) when condition schema context node. Does not log.
5750 *
5751 * @param[in] schema Schema node with the when condition.
5752 * @param[out] ctx_snode When schema context node.
5753 * @param[out] ctx_snode_type Schema context node type.
5754 */
5755void
5756resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5757{
5758 const struct lys_node *sparent;
5759
5760 /* find a not schema-only node */
5761 *ctx_snode_type = LYXP_NODE_ELEM;
5762 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5763 if (schema->nodetype == LYS_AUGMENT) {
5764 sparent = ((struct lys_node_augment *)schema)->target;
5765 } else {
5766 sparent = schema->parent;
5767 }
5768 if (!sparent) {
5769 /* context node is the document root (fake root in our case) */
5770 if (schema->flags & LYS_CONFIG_W) {
5771 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5772 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005773 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005774 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005775 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskocb45f472018-02-12 10:47:42 +01005776 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
Michal Vasko508a50d2016-09-07 14:50:33 +02005777 break;
5778 }
5779 schema = sparent;
5780 }
5781
5782 *ctx_snode = (struct lys_node *)schema;
5783}
5784
5785/**
Michal Vaskocf024702015-10-08 15:01:42 +02005786 * @brief Resolve (find) when condition context node. Does not log.
5787 *
5788 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005789 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005790 * @param[out] ctx_node Context node.
5791 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005792 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005793 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005794 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005795static int
5796resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5797 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005798{
Michal Vaskocf024702015-10-08 15:01:42 +02005799 struct lyd_node *parent;
5800 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005801 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005802 uint16_t i, data_depth, schema_depth;
5803
Michal Vasko508a50d2016-09-07 14:50:33 +02005804 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005805
Michal Vaskofe989752016-09-08 08:47:26 +02005806 if (node_type == LYXP_NODE_ELEM) {
5807 /* standard element context node */
5808 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5809 for (sparent = schema, schema_depth = 0;
5810 sparent;
5811 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5812 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5813 ++schema_depth;
5814 }
Michal Vaskocf024702015-10-08 15:01:42 +02005815 }
Michal Vaskofe989752016-09-08 08:47:26 +02005816 if (data_depth < schema_depth) {
5817 return -1;
5818 }
Michal Vaskocf024702015-10-08 15:01:42 +02005819
Michal Vasko956e8542016-08-26 09:43:35 +02005820 /* find the corresponding data node */
5821 for (i = 0; i < data_depth - schema_depth; ++i) {
5822 node = node->parent;
5823 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005824 if (node->schema != schema) {
5825 return -1;
5826 }
Michal Vaskofe989752016-09-08 08:47:26 +02005827 } else {
5828 /* root context node */
5829 while (node->parent) {
5830 node = node->parent;
5831 }
5832 while (node->prev->next) {
5833 node = node->prev;
5834 }
Michal Vaskocf024702015-10-08 15:01:42 +02005835 }
5836
Michal Vaskoa59495d2016-08-22 09:18:58 +02005837 *ctx_node = node;
5838 *ctx_node_type = node_type;
5839 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005840}
5841
Michal Vasko76c3bd32016-08-24 16:02:52 +02005842/**
5843 * @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 +01005844 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005845 *
5846 * @param[in] snode Schema node, whose children instances need to be unlinked.
5847 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5848 * it is moved to point to another sibling still in the original tree.
5849 * @param[in,out] ctx_node When context node, adjusted if needed.
5850 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5851 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5852 * Ordering may change, but there will be no semantic change.
5853 *
5854 * @return EXIT_SUCCESS on success, -1 on error.
5855 */
5856static int
5857resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5858 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5859{
5860 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005861 const struct lys_node *slast;
Michal Vasko53b7da02018-02-13 15:28:42 +01005862 struct ly_ctx *ctx = snode->module->ctx;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005863
5864 switch (snode->nodetype) {
5865 case LYS_AUGMENT:
5866 case LYS_USES:
5867 case LYS_CHOICE:
5868 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005869 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005870 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005871 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5872 continue;
5873 }
5874
5875 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005876 return -1;
5877 }
5878 }
5879 break;
5880 case LYS_CONTAINER:
5881 case LYS_LIST:
5882 case LYS_LEAF:
5883 case LYS_LEAFLIST:
5884 case LYS_ANYXML:
5885 case LYS_ANYDATA:
5886 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5887 if (elem->schema == snode) {
5888
5889 if (elem == *ctx_node) {
5890 /* We are going to unlink our context node! This normally cannot happen,
5891 * but we use normal top-level data nodes for faking a document root node,
5892 * so if this is the context node, we just use the next top-level node.
5893 * Additionally, it can even happen that there are no top-level data nodes left,
5894 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5895 * lyxp_eval() can handle this special situation.
5896 */
5897 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005898 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005899 return -1;
5900 }
5901
5902 if (elem->prev == elem) {
5903 /* unlinking last top-level element, use an empty data tree */
5904 *ctx_node = NULL;
5905 } else {
5906 /* in this case just use the previous/last top-level data node */
5907 *ctx_node = elem->prev;
5908 }
5909 } else if (elem == *node) {
5910 /* We are going to unlink the currently processed node. This does not matter that
5911 * much, but we would lose access to the original data tree, so just move our
5912 * pointer somewhere still inside it.
5913 */
5914 if ((*node)->prev != *node) {
5915 *node = (*node)->prev;
5916 } else {
5917 /* the processed node with sibings were all unlinked, oh well */
5918 *node = NULL;
5919 }
5920 }
5921
5922 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005923 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005924 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005925 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005926 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005927 return -1;
5928 }
5929 } else {
5930 *unlinked_nodes = elem;
5931 }
5932
5933 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5934 /* there can be only one instance */
5935 break;
5936 }
5937 }
5938 }
5939 break;
5940 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01005941 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005942 return -1;
5943 }
5944
5945 return EXIT_SUCCESS;
5946}
5947
5948/**
5949 * @brief Relink the unlinked nodes back.
5950 *
5951 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5952 * we simply need a sibling from the original data tree.
5953 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5954 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5955 * or the sibling of \p unlinked_nodes.
5956 *
5957 * @return EXIT_SUCCESS on success, -1 on error.
5958 */
5959static int
5960resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5961{
5962 struct lyd_node *elem;
5963
5964 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005965 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005966 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005967 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005968 return -1;
5969 }
5970 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005971 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005972 return -1;
5973 }
5974 }
5975 }
5976
5977 return EXIT_SUCCESS;
5978}
5979
Radek Krejci03b71f72016-03-16 11:10:09 +01005980int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005981resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005982{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005983 int ret = 0;
5984 uint8_t must_size;
5985 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005986
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005987 assert(node);
5988
5989 schema = node->schema;
5990
5991 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005992 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005993 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005994 must_size = ((struct lys_node_container *)schema)->must_size;
5995 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005996 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005997 must_size = ((struct lys_node_leaf *)schema)->must_size;
5998 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005999 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006000 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6001 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006002 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006003 must_size = ((struct lys_node_list *)schema)->must_size;
6004 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006005 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02006006 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006007 must_size = ((struct lys_node_anydata *)schema)->must_size;
6008 break;
6009 case LYS_NOTIF:
6010 must_size = ((struct lys_node_notif *)schema)->must_size;
6011 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006012 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006013 must_size = 0;
6014 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006015 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006016
6017 if (must_size) {
6018 ++ret;
6019 }
6020
6021 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6022 if (!node->prev->next) {
6023 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6024 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6025 ret += 0x2;
6026 }
6027 }
6028
6029 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006030}
6031
6032int
Radek Krejci46165822016-08-26 14:06:27 +02006033resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006034{
Radek Krejci46165822016-08-26 14:06:27 +02006035 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006036
Radek Krejci46165822016-08-26 14:06:27 +02006037 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006038
Radek Krejci46165822016-08-26 14:06:27 +02006039 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006040 return 1;
6041 }
6042
Radek Krejci46165822016-08-26 14:06:27 +02006043 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006044 goto check_augment;
6045
Radek Krejci46165822016-08-26 14:06:27 +02006046 while (parent) {
6047 /* stop conditions */
6048 if (!mode) {
6049 /* stop on node that can be instantiated in data tree */
6050 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6051 break;
6052 }
6053 } else {
6054 /* stop on the specified node */
6055 if (parent == stop) {
6056 break;
6057 }
6058 }
6059
6060 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006061 return 1;
6062 }
6063check_augment:
6064
6065 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006066 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006067 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006068 }
6069 parent = lys_parent(parent);
6070 }
6071
6072 return 0;
6073}
6074
Michal Vaskocf024702015-10-08 15:01:42 +02006075/**
6076 * @brief Resolve (check) all when conditions relevant for \p node.
6077 * Logs directly.
6078 *
6079 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02006080 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6081 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02006082 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006083 * @return
6084 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02006085 * 0 - all "when" statements true
6086 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01006087 * 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 +02006088 */
Radek Krejci46165822016-08-26 14:06:27 +02006089int
Michal Vasko0b963112017-08-11 12:45:36 +02006090resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02006091{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006092 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006093 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006094 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006095 enum lyxp_node_type ctx_node_type;
Michal Vasko53b7da02018-02-13 15:28:42 +01006096 struct ly_ctx *ctx = node->schema->module->ctx;
Radek Krejci51093642016-03-29 10:14:59 +02006097 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006098
6099 assert(node);
6100 memset(&set, 0, sizeof set);
6101
Michal Vasko78d97e22017-02-21 09:54:38 +01006102 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006103 /* make the node dummy for the evaluation */
6104 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006105 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6106 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006107 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006108 if (rc) {
6109 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006110 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006111 }
Radek Krejci51093642016-03-29 10:14:59 +02006112 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006113 }
6114
Radek Krejci03b71f72016-03-16 11:10:09 +01006115 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006116 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006117 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006118 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006119 if ((ignore_fail == 1)
6120 || ((((struct lys_node_container *)node->schema)->when->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006121 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6122 ((struct lys_node_container *)node->schema)->when->cond);
6123 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006124 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006125 if (failed_when) {
6126 *failed_when = ((struct lys_node_container *)node->schema)->when;
6127 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006128 goto cleanup;
6129 }
Michal Vaskocf024702015-10-08 15:01:42 +02006130 }
Radek Krejci51093642016-03-29 10:14:59 +02006131
6132 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006133 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006134 }
6135
Michal Vasko90fc2a32016-08-24 15:58:58 +02006136 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006137 goto check_augment;
6138
6139 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006140 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6141 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006142 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006143 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006144 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006145 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006146 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006147 }
6148 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006149
6150 unlinked_nodes = NULL;
6151 /* we do not want our node pointer to change */
6152 tmp_node = node;
6153 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6154 if (rc) {
6155 goto cleanup;
6156 }
6157
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006158 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6159 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006160
6161 if (unlinked_nodes && ctx_node) {
6162 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6163 rc = -1;
6164 goto cleanup;
6165 }
6166 }
6167
Radek Krejci03b71f72016-03-16 11:10:09 +01006168 if (rc) {
6169 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006170 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006171 }
Radek Krejci51093642016-03-29 10:14:59 +02006172 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006173 }
6174
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006175 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006176 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02006177 if ((ignore_fail == 1)
6178 || ((((struct lys_node_uses *)sparent)->when->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006179 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6180 ((struct lys_node_uses *)sparent)->when->cond);
6181 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006182 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko53b7da02018-02-13 15:28:42 +01006183 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006184 if (failed_when) {
6185 *failed_when = ((struct lys_node_uses *)sparent)->when;
6186 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006187 goto cleanup;
6188 }
Michal Vaskocf024702015-10-08 15:01:42 +02006189 }
Radek Krejci51093642016-03-29 10:14:59 +02006190
6191 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006192 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006193 }
6194
6195check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006196 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006197 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006198 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006199 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006200 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006201 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006202 }
6203 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006204
6205 unlinked_nodes = NULL;
6206 tmp_node = node;
6207 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6208 if (rc) {
6209 goto cleanup;
6210 }
6211
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006212 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6213 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006214
6215 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6216 * so the tree did not actually change and there is nothing for us to do
6217 */
6218 if (unlinked_nodes && ctx_node) {
6219 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6220 rc = -1;
6221 goto cleanup;
6222 }
6223 }
6224
Radek Krejci03b71f72016-03-16 11:10:09 +01006225 if (rc) {
6226 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006227 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006228 }
Radek Krejci51093642016-03-29 10:14:59 +02006229 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006230 }
6231
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006232 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006233 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006234 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006235 if ((ignore_fail == 1)
6236 || ((((struct lys_node_augment *)sparent->parent)->when->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006237 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006238 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006239 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006240 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006241 if (failed_when) {
6242 *failed_when = ((struct lys_node_augment *)sparent->parent)->when;
6243 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006244 goto cleanup;
6245 }
Michal Vaskocf024702015-10-08 15:01:42 +02006246 }
Radek Krejci51093642016-03-29 10:14:59 +02006247
6248 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006249 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006250 }
6251
Michal Vasko90fc2a32016-08-24 15:58:58 +02006252 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006253 }
6254
Radek Krejci0b7704f2016-03-18 12:16:14 +01006255 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006256
Radek Krejci51093642016-03-29 10:14:59 +02006257cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006258 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006259 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006260 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006261}
6262
Radek Krejcicbb473e2016-09-16 14:48:32 +02006263static int
6264check_leafref_features(struct lys_type *type)
6265{
6266 struct lys_node *iter;
6267 struct ly_set *src_parents, *trg_parents, *features;
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006268 struct lys_node_augment *aug;
Michal Vasko53b7da02018-02-13 15:28:42 +01006269 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006270 unsigned int i, j, size, x;
6271 int ret = EXIT_SUCCESS;
6272
6273 assert(type->parent);
6274
6275 src_parents = ly_set_new();
6276 trg_parents = ly_set_new();
6277 features = ly_set_new();
6278
6279 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006280 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006281 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6282 continue;
6283 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006284 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006285 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006286 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006287 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006288 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006289 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006290 ret = EXIT_FAILURE;
6291 goto cleanup;
6292 }
6293 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006294 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6295 }
6296 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006297 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006298 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6299 continue;
6300 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006301 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006302 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006303 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006304 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006305 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006306 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006307 ret = EXIT_FAILURE;
6308 goto cleanup;
6309 }
6310 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006311 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6312 }
6313
6314 /* compare the features used in if-feature statements in the rest of both
6315 * chains of parents. The set of features used for target must be a subset
6316 * of features used for the leafref. This is not a perfect, we should compare
6317 * the truth tables but it could require too much resources, so we simplify that */
6318 for (i = 0; i < src_parents->number; i++) {
6319 iter = src_parents->set.s[i]; /* shortcut */
6320 if (!iter->iffeature_size) {
6321 continue;
6322 }
6323 for (j = 0; j < iter->iffeature_size; j++) {
6324 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6325 for (; size; size--) {
6326 if (!iter->iffeature[j].features[size - 1]) {
6327 /* not yet resolved feature, postpone this check */
6328 ret = EXIT_FAILURE;
6329 goto cleanup;
6330 }
6331 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6332 }
6333 }
6334 }
6335 x = features->number;
6336 for (i = 0; i < trg_parents->number; i++) {
6337 iter = trg_parents->set.s[i]; /* shortcut */
6338 if (!iter->iffeature_size) {
6339 continue;
6340 }
6341 for (j = 0; j < iter->iffeature_size; j++) {
6342 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6343 for (; size; size--) {
6344 if (!iter->iffeature[j].features[size - 1]) {
6345 /* not yet resolved feature, postpone this check */
6346 ret = EXIT_FAILURE;
6347 goto cleanup;
6348 }
Michal Vasko53b7da02018-02-13 15:28:42 +01006349 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006350 /* the feature is not present in features set of target's parents chain */
Michal Vasko53b7da02018-02-13 15:28:42 +01006351 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
6352 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006353 "Leafref is not conditional based on \"%s\" feature as its target.",
6354 iter->iffeature[j].features[size - 1]->name);
6355 ret = -1;
6356 goto cleanup;
6357 }
6358 }
6359 }
6360 }
6361
6362cleanup:
6363 ly_set_free(features);
6364 ly_set_free(src_parents);
6365 ly_set_free(trg_parents);
6366
6367 return ret;
6368}
6369
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006370static int
6371check_type_union_leafref(struct lys_type *type)
6372{
6373 uint8_t i;
6374
6375 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6376 /* go through unions and look for leafref */
6377 for (i = 0; i < type->info.uni.count; ++i) {
6378 switch (type->info.uni.types[i].base) {
6379 case LY_TYPE_LEAFREF:
6380 return 1;
6381 case LY_TYPE_UNION:
6382 if (check_type_union_leafref(&type->info.uni.types[i])) {
6383 return 1;
6384 }
6385 break;
6386 default:
6387 break;
6388 }
6389 }
6390
6391 return 0;
6392 }
6393
6394 /* just inherit the flag value */
6395 return type->der->has_union_leafref;
6396}
6397
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006398/**
Michal Vaskobb211122015-08-19 14:03:11 +02006399 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006400 *
6401 * @param[in] mod Main module.
6402 * @param[in] item Item to resolve. Type determined by \p type.
6403 * @param[in] type Type of the unresolved item.
6404 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006405 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006406 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006407 *
6408 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6409 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006410static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006411resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006412 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006413{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006414 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Michal Vasko53b7da02018-02-13 15:28:42 +01006415 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006416 unsigned int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01006417 struct ly_ctx * ctx = mod->ctx;
Radek Krejci80056d52017-01-05 13:13:33 +01006418 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006419 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006420 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006421
Radek Krejcic79c6b12016-07-26 15:11:49 +02006422 struct ly_set *refs, *procs;
6423 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006424 struct lys_ident *ident;
6425 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006426 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006427 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006428 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006429 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006430 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006431 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006432 struct lys_ext_instance *ext, **extlist;
6433 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006434
6435 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006436 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006437 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006438 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006439 ident = item;
6440
Radek Krejci018f1f52016-08-03 16:01:20 +02006441 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006442 break;
6443 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006444 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006445 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006446 stype = item;
6447
Radek Krejci018f1f52016-08-03 16:01:20 +02006448 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006449 break;
6450 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006451 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006452 stype = item;
6453
Michal Vasko1c007172017-03-10 10:20:44 +01006454 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6455 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006456 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006457
Michal Vaskobb520442017-05-23 10:55:18 +02006458 if (lys_node_module(node)->implemented) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006459 /* make all the modules in the path implemented */
Michal Vaskobb520442017-05-23 10:55:18 +02006460 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6461 if (!lys_node_module(next)->implemented) {
6462 if (lys_set_implemented(lys_node_module(next))) {
6463 rc = -1;
6464 break;
6465 }
6466 }
6467 }
6468 if (next) {
6469 break;
6470 }
6471
6472 /* store the backlink from leafref target */
6473 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6474 rc = -1;
Michal Vaskobe136f62017-09-21 12:08:39 +02006475 break;
6476 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006477 }
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006478
6479 /* check if leafref and its target are under common if-features */
6480 rc = check_leafref_features(stype);
Radek Krejci46c4cd72016-01-21 15:13:52 +01006481 }
6482
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006483 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006484 case UNRES_TYPE_DER_EXT:
6485 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006486 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006487 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006488 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006489 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006490 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006491 /* parent */
6492 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006493 stype = item;
6494
Michal Vasko88c29542015-11-27 14:57:53 +01006495 /* HACK type->der is temporarily unparsed type statement */
6496 yin = (struct lyxml_elem *)stype->der;
6497 stype->der = NULL;
6498
Pavol Vicana0e4e672016-02-24 12:20:04 +01006499 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6500 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006501 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006502
6503 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006504 /* may try again later */
6505 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006506 } else {
6507 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006508 lydict_remove(ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006509 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006510 }
6511
Michal Vasko88c29542015-11-27 14:57:53 +01006512 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006513 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006514 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006515 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006516 lyxml_free(ctx, yin);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006517 } else {
6518 /* may try again later, put all back how it was */
6519 stype->der = (struct lys_tpdf *)yin;
6520 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006521 }
Radek Krejcic13db382016-08-16 10:52:42 +02006522 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006523 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006524 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006525 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
Radek Krejci2c2fce82016-08-01 13:52:26 +02006526 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006527
6528 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6529 /* fill typedef union leafref flag */
6530 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6531 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6532 /* copy the type in case it has union leafref flag */
6533 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006534 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006535 return -1;
6536 }
6537 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006538 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006539 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6540 * 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 +02006541 * grouping. The grouping cannot be used unless the unres counter is 0.
6542 * To remember that the grouping already increased the counter, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006543 * of the type's base member. */
6544 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6545 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006546 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006547 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006548 return -1;
6549 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006550 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006551 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006552 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006553 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006554 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006555 iff_data = str_snode;
6556 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006557 if (!rc) {
6558 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006559 if (iff_data->infeature) {
6560 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6561 feat = *((struct lys_feature **)item);
6562 if (!feat->depfeatures) {
6563 feat->depfeatures = ly_set_new();
6564 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006565 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006566 }
6567 /* cleanup temporary data */
Michal Vasko53b7da02018-02-13 15:28:42 +01006568 lydict_remove(ctx, iff_data->fname);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006569 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006570 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006571 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006572 case UNRES_FEATURE:
6573 feat = (struct lys_feature *)item;
6574
6575 if (feat->iffeature_size) {
6576 refs = ly_set_new();
6577 procs = ly_set_new();
6578 ly_set_add(procs, feat, 0);
6579
6580 while (procs->number) {
6581 ref = procs->set.g[procs->number - 1];
6582 ly_set_rm_index(procs, procs->number - 1);
6583
6584 for (i = 0; i < ref->iffeature_size; i++) {
6585 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6586 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006587 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006588 if (ref->iffeature[i].features[j - 1] == feat) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006589 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006590 goto featurecheckdone;
6591 }
6592
6593 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6594 k = refs->number;
6595 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6596 /* not yet seen feature, add it for processing */
6597 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6598 }
6599 }
6600 } else {
6601 /* forward reference */
6602 rc = EXIT_FAILURE;
6603 goto featurecheckdone;
6604 }
6605 }
6606
6607 }
6608 }
6609 rc = EXIT_SUCCESS;
6610
6611featurecheckdone:
6612 ly_set_free(refs);
6613 ly_set_free(procs);
6614 }
6615
6616 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006617 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006618 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006619 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006620 case UNRES_TYPEDEF_DFLT:
6621 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006622 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006623 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006624 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006625 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006626 break;
6627 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006628 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006629 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006630 choic = item;
6631
Radek Krejcie00d2312016-08-12 15:27:49 +02006632 if (!choic->dflt) {
6633 choic->dflt = resolve_choice_dflt(choic, expr);
6634 }
Michal Vasko7955b362015-09-04 14:18:15 +02006635 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006636 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006637 } else {
6638 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006639 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006640 break;
6641 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006642 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006643 break;
6644 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006645 unique_info = (struct unres_list_uniq *)item;
6646 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006647 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006648 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006649 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006650 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006651 case UNRES_XPATH:
6652 node = (struct lys_node *)item;
Michal Vaskof96dfb62017-08-17 12:23:49 +02006653 rc = lys_check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006654 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006655 case UNRES_EXT:
6656 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006657 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006658 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006659 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006660 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006661 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006662 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006663 if (eplugin) {
6664 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006665 u = malloc(sizeof *u);
Michal Vasko53b7da02018-02-13 15:28:42 +01006666 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006667 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006668 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6669 /* something really bad happend since the extension finalization is not actually
6670 * being resolved while adding into unres, so something more serious with the unres
6671 * list itself must happened */
6672 return -1;
6673 }
Radek Krejci80056d52017-01-05 13:13:33 +01006674 }
6675 }
Radek Krejci79685c92017-02-17 10:49:43 +01006676 }
6677 if (!rc || rc == -1) {
6678 /* cleanup on success or fatal error */
6679 if (ext_data->datatype == LYS_IN_YIN) {
6680 /* YIN */
Michal Vasko53b7da02018-02-13 15:28:42 +01006681 lyxml_free(ctx, ext_data->data.yin);
Radek Krejci79685c92017-02-17 10:49:43 +01006682 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006683 /* YANG */
6684 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006685 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006686 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006687 }
6688 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006689 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006690 u = (uint8_t *)str_snode;
6691 ext = (*(struct lys_ext_instance ***)item)[*u];
6692 free(u);
6693
Radek Krejci80056d52017-01-05 13:13:33 +01006694 eplugin = ext->def->plugin;
6695
6696 /* inherit */
6697 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6698 root = (struct lys_node *)ext->parent;
6699 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6700 LY_TREE_DFS_BEGIN(root->child, next, node) {
6701 /* first, check if the node already contain instance of the same extension,
6702 * in such a case we won't inherit. In case the node was actually defined as
6703 * augment data, we are supposed to check the same way also the augment node itself */
6704 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6705 goto inherit_dfs_sibling;
6706 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6707 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6708 goto inherit_dfs_sibling;
6709 }
6710
6711 if (eplugin->check_inherit) {
6712 /* we have a callback to check the inheritance, use it */
6713 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6714 case 0:
6715 /* yes - continue with the inheriting code */
6716 break;
6717 case 1:
6718 /* no - continue with the node's sibling */
6719 goto inherit_dfs_sibling;
6720 case 2:
6721 /* no, but continue with the children, just skip the inheriting code for this node */
6722 goto inherit_dfs_child;
6723 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006724 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
Radek Krejci80056d52017-01-05 13:13:33 +01006725 ext->def->module->name, ext->def->name, rc);
6726 }
6727 }
6728
6729 /* inherit the extension */
6730 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Michal Vasko53b7da02018-02-13 15:28:42 +01006731 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006732 extlist[node->ext_size] = malloc(sizeof **extlist);
Michal Vasko53b7da02018-02-13 15:28:42 +01006733 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006734 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6735 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6736
6737 node->ext = extlist;
6738 node->ext_size++;
6739
6740inherit_dfs_child:
6741 /* modification of - select element for the next run - children first */
6742 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6743 next = NULL;
6744 } else {
6745 next = node->child;
6746 }
6747 if (!next) {
6748inherit_dfs_sibling:
6749 /* no children, try siblings */
6750 next = node->next;
6751 }
6752 while (!next) {
6753 /* go to the parent */
6754 node = lys_parent(node);
6755
6756 /* we are done if we are back in the root (the starter's parent */
6757 if (node == root) {
6758 break;
6759 }
6760
6761 /* parent is already processed, go to its sibling */
6762 next = node->next;
6763 }
6764 }
6765 }
6766 }
6767
6768 /* final check */
6769 if (eplugin->check_result) {
6770 if ((*eplugin->check_result)(ext)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006771 LOGERR(ctx, LY_EEXT, "Resolving extension failed.");
Radek Krejci80056d52017-01-05 13:13:33 +01006772 return -1;
6773 }
6774 }
6775
6776 rc = 0;
6777 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006778 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006779 LOGINT(ctx);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006780 break;
6781 }
6782
Radek Krejci54081ce2016-08-12 15:21:47 +02006783 if (has_str && !rc) {
6784 /* the string is no more needed in case of success.
6785 * In case of forward reference, we will try to resolve the string later */
Michal Vasko53b7da02018-02-13 15:28:42 +01006786 lydict_remove(ctx, str_snode);
Radek Krejci4f78b532016-02-17 13:43:00 +01006787 }
6788
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006789 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006790}
6791
Michal Vaskof02e3742015-08-05 16:27:02 +02006792/* logs directly */
6793static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006794print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006795{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006796 struct lyxml_elem *xml;
6797 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006798 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006799 const char *name = NULL;
6800 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006801
Michal Vaskof02e3742015-08-05 16:27:02 +02006802 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006803 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006804 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006805 break;
6806 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006807 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006808 break;
6809 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006810 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6811 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006812 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006813 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006814 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006815 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006816 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6817 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006818 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006819 } else {
6820 LY_TREE_FOR(xml->attr, attr) {
6821 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006822 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006823 break;
6824 }
6825 }
6826 assert(attr);
6827 }
Radek Krejcie534c132016-11-23 13:32:31 +01006828 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006829 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006830 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006831 iff_data = str_node;
6832 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006833 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006834 case UNRES_FEATURE:
6835 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6836 ((struct lys_feature *)item)->name);
6837 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006838 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006839 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006840 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006841 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006842 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006843 if (str_node) {
6844 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6845 } /* else no default value in the type itself, but we are checking some restrictions against
6846 * possible default value of some base type. The failure is caused by not resolved base type,
6847 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006848 break;
6849 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006850 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006851 break;
6852 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006853 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006854 break;
6855 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006856 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006857 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006858 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006859 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6860 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006861 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006862 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006863 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6864 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006865 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006866 case UNRES_EXT:
6867 extinfo = (struct unres_ext *)str_node;
6868 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6869 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6870 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006871 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006872 LOGINT(NULL);
Michal Vaskof02e3742015-08-05 16:27:02 +02006873 break;
6874 }
6875}
6876
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006877/**
Michal Vaskobb211122015-08-19 14:03:11 +02006878 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006879 *
6880 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006881 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006882 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006883 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006884 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006885int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006886resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006887{
Radek Krejci010e54b2016-03-15 09:40:34 +01006888 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko53b7da02018-02-13 15:28:42 +01006889 struct ly_err_item *prev_eitem;
6890 enum int_log_opts prev_ilo;
6891 LY_ERR prev_ly_errno;
6892 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006893
6894 assert(unres);
6895
Michal Vaskoe8734262016-09-29 14:12:06 +02006896 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01006897 prev_ly_errno = ly_errno;
6898 ly_ilo_change(mod->ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02006899
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006900 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006901 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006902 unres_count = 0;
6903 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006904
6905 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006906 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006907 * if-features are resolved here to make sure that we will have all if-features for
6908 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006909 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006910 continue;
6911 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006912 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006913 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006914
Michal Vasko88c29542015-11-27 14:57:53 +01006915 ++unres_count;
Michal Vaskof96dfb62017-08-17 12:23:49 +02006916 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 +02006917 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006918 unres->type[i] = UNRES_RESOLVED;
6919 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006920 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006921 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006922 goto error;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006923 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006924 /* forward reference, erase errors */
6925 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02006926 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006927 }
Michal Vasko88c29542015-11-27 14:57:53 +01006928 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006929
Michal Vasko88c29542015-11-27 14:57:53 +01006930 if (res_count < unres_count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006931 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
6932 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006933
6934 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006935 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006936 continue;
6937 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02006938 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006939 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006940 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006941 }
6942
Michal Vaskof96dfb62017-08-17 12:23:49 +02006943 /* the rest except finalizing extensions and xpath */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006944 for (i = 0; i < unres->count; ++i) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02006945 if ((unres->type[i] == UNRES_RESOLVED) || (unres->type[i] == UNRES_EXT_FINALIZE) || (unres->type[i] == UNRES_XPATH)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006946 continue;
6947 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006948
Michal Vaskof96dfb62017-08-17 12:23:49 +02006949 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 +01006950 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006951 if (unres->type[i] == UNRES_LIST_UNIQ) {
6952 /* free the allocated structure */
6953 free(unres->item[i]);
6954 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006955 unres->type[i] = UNRES_RESOLVED;
6956 ++resolved;
6957 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006958 goto error;
Radek Krejci791f6c72017-02-22 15:23:39 +01006959 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006960 /* forward reference, erase errors */
6961 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006962 }
6963 }
6964
Michal Vasko53b7da02018-02-13 15:28:42 +01006965 /* log normally now */
6966 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
6967 ly_errno = prev_ly_errno;
Radek Krejci010e54b2016-03-15 09:40:34 +01006968
Radek Krejci80056d52017-01-05 13:13:33 +01006969 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6970 for (i = 0; i < unres->count; ++i) {
6971 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6972 continue;
6973 }
6974
Michal Vaskof96dfb62017-08-17 12:23:49 +02006975 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 +01006976 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006977 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006978 ++resolved;
6979 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006980 /* else error - it was already printed, but resolved was not increased,
6981 so this unres item will not be resolved again in the following code,
6982 but it will cause returning -1 at the end, this way we are able to
6983 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006984 }
6985
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006986 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006987 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
Michal Vaskof96dfb62017-08-17 12:23:49 +02006988 * all the validation errors, xpath is resolved only here to properly print all the messages
Radek Krejci010e54b2016-03-15 09:40:34 +01006989 */
6990 for (i = 0; i < unres->count; ++i) {
6991 if (unres->type[i] == UNRES_RESOLVED) {
6992 continue;
6993 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02006994 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 +01006995 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006996 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006997 unres->type[i] = UNRES_RESOLVED;
6998 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006999 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007000 }
Radek Krejcib3142312016-11-09 11:04:12 +01007001 if (resolved < unres->count) {
7002 return -1;
7003 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007004 }
7005
Michal Vaskoe8734262016-09-29 14:12:06 +02007006 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01007007 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007008 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01007009
7010error:
7011 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 1);
7012 /* ly_errno will be set accordingly, we do not want to keep the previous value */
7013 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007014}
7015
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007016/**
Michal Vaskobb211122015-08-19 14:03:11 +02007017 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007018 *
7019 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007020 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007021 * @param[in] item Item to resolve. Type determined by \p type.
7022 * @param[in] type Type of the unresolved item.
7023 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007024 *
Michal Vasko3767fb22016-07-21 12:10:57 +02007025 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007026 */
7027int
Radek Krejci48464ed2016-03-17 15:44:09 +01007028unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7029 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007030{
Radek Krejci54081ce2016-08-12 15:21:47 +02007031 int rc;
7032 const char *dictstr;
7033
7034 dictstr = lydict_insert(mod->ctx, str, 0);
7035 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7036
Radek Krejcid9c0ce22017-01-20 15:20:16 +01007037 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02007038 lydict_remove(mod->ctx, dictstr);
7039 }
7040 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007041}
7042
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007043/**
Michal Vaskobb211122015-08-19 14:03:11 +02007044 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007045 *
7046 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007047 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007048 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01007049 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007050 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007051 *
Radek Krejci62f7aad2017-10-26 14:53:52 +02007052 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007053 */
7054int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007055unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01007056 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007057{
Michal Vasko53b7da02018-02-13 15:28:42 +01007058 int rc;
Radek Krejci62f7aad2017-10-26 14:53:52 +02007059 uint32_t u;
Michal Vasko53b7da02018-02-13 15:28:42 +01007060 enum int_log_opts prev_ilo;
7061 struct ly_err_item *prev_eitem;
7062 LY_ERR prev_ly_errno;
Michal Vasko88c29542015-11-27 14:57:53 +01007063 struct lyxml_elem *yin;
Michal Vasko53b7da02018-02-13 15:28:42 +01007064 struct ly_ctx *ctx = mod->ctx;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007065
Michal Vasko9bf425b2015-10-22 11:42:03 +02007066 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
7067 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007068
Radek Krejci850a5de2016-11-08 14:06:40 +01007069 /* check for duplicities in unres */
7070 for (u = 0; u < unres->count; u++) {
7071 if (unres->type[u] == type && unres->item[u] == item &&
7072 unres->str_snode[u] == snode && unres->module[u] == mod) {
Radek Krejci62f7aad2017-10-26 14:53:52 +02007073 /* duplication can happen when the node contains multiple statements of the same type to check,
7074 * this can happen for example when refinement is being applied, so we just postpone the processing
7075 * and do not duplicate the information */
7076 return EXIT_FAILURE;
Radek Krejci850a5de2016-11-08 14:06:40 +01007077 }
7078 }
7079
Michal Vaskof96dfb62017-08-17 12:23:49 +02007080 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH)) {
7081 /* extension finalization is not even tried when adding the item into the inres list,
7082 * xpath is not tried because it would hide some potential warnings */
Radek Krejcic293bac2017-02-27 11:25:28 +01007083 rc = EXIT_FAILURE;
7084 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007085 prev_ly_errno = ly_errno;
7086 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007087
Michal Vasko53b7da02018-02-13 15:28:42 +01007088 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01007089 if (rc != EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007090 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7091 if (rc != -1) {
7092 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007093 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007094
Radek Krejci80056d52017-01-05 13:13:33 +01007095 if (type == UNRES_LIST_UNIQ) {
7096 /* free the allocated structure */
7097 free(item);
7098 } else if (rc == -1 && type == UNRES_IFFEAT) {
7099 /* free the allocated resources */
7100 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007101 }
Radek Krejci80056d52017-01-05 13:13:33 +01007102 return rc;
7103 } else {
7104 /* erase info about validation errors */
Michal Vasko53b7da02018-02-13 15:28:42 +01007105 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7106 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007107 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007108
Radek Krejci80056d52017-01-05 13:13:33 +01007109 print_unres_schema_item_fail(item, type, snode);
7110
7111 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7112 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7113 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7114 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7115 lyxml_unlink_elem(mod->ctx, yin, 1);
7116 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7117 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007118 }
Michal Vasko88c29542015-11-27 14:57:53 +01007119 }
7120
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007121 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007122 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Michal Vasko53b7da02018-02-13 15:28:42 +01007123 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007124 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007125 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007126 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007127 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007128 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko53b7da02018-02-13 15:28:42 +01007129 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007130 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007131 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01007132 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007133 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007134
Michal Vasko3767fb22016-07-21 12:10:57 +02007135 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007136}
7137
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007138/**
Michal Vaskobb211122015-08-19 14:03:11 +02007139 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007140 *
7141 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007142 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007143 * @param[in] item Old item to be resolved.
7144 * @param[in] type Type of the old unresolved item.
7145 * @param[in] new_item New item to use in the duplicate.
7146 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007147 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007148 */
Michal Vaskodad19402015-08-06 09:51:53 +02007149int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007150unres_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 +02007151{
7152 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007153 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007154 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007155
Michal Vaskocf024702015-10-08 15:01:42 +02007156 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007157
Radek Krejcid09d1a52016-08-11 14:05:45 +02007158 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7159 if (type == UNRES_LIST_UNIQ) {
7160 aux_uniq.list = item;
7161 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7162 item = &aux_uniq;
7163 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007164 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007165
7166 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007167 if (type == UNRES_LIST_UNIQ) {
7168 free(new_item);
7169 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007170 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007171 }
7172
Radek Krejcic79c6b12016-07-26 15:11:49 +02007173 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007174 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007175 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007176 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007177 return -1;
7178 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007179 } else if (type == UNRES_IFFEAT) {
7180 /* duplicate unres_iffeature_data */
7181 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01007182 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007183 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7184 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7185 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007186 LOGINT(mod->ctx);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007187 return -1;
7188 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007189 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007190 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007191 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007192 return -1;
7193 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007194 }
Michal Vaskodad19402015-08-06 09:51:53 +02007195
7196 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007197}
7198
Michal Vaskof02e3742015-08-05 16:27:02 +02007199/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007200int
Michal Vasko878e38d2016-09-05 12:17:53 +02007201unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007202{
Michal Vasko878e38d2016-09-05 12:17:53 +02007203 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007204 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007205
Radek Krejciddddd0d2017-01-20 15:20:46 +01007206 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007207 i = start_on_backwards;
7208 } else {
7209 i = unres->count - 1;
7210 }
7211 for (; i > -1; i--) {
7212 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007213 continue;
7214 }
7215 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007216 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007217 break;
7218 }
7219 } else {
7220 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7221 aux_uniq2 = (struct unres_list_uniq *)item;
7222 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007223 break;
7224 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007225 }
7226 }
7227
Michal Vasko878e38d2016-09-05 12:17:53 +02007228 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007229}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007230
Michal Vaskoede9c472016-06-07 09:38:15 +02007231static void
7232unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7233{
7234 struct lyxml_elem *yin;
7235 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007236 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007237
7238 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007239 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007240 case UNRES_TYPE_DER:
7241 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7242 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7243 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007244 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007245 lydict_remove(ctx, yang->name);
7246 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007247 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7248 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7249 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007250 } else {
7251 lyxml_free(ctx, yin);
7252 }
7253 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007254 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007255 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7256 lydict_remove(ctx, iff_data->fname);
7257 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007258 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007259 case UNRES_IDENT:
7260 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007261 case UNRES_CHOICE_DFLT:
7262 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007263 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7264 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007265 case UNRES_LIST_UNIQ:
7266 free(unres->item[i]);
7267 break;
PavolVicanc1807262017-01-31 18:00:27 +01007268 case UNRES_EXT:
7269 free(unres->str_snode[i]);
7270 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007271 default:
7272 break;
7273 }
7274 unres->type[i] = UNRES_RESOLVED;
7275}
7276
Michal Vasko88c29542015-11-27 14:57:53 +01007277void
Michal Vasko44ab1462017-05-18 13:18:36 +02007278unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007279{
7280 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007281 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007282
Radek Krejcic071c542016-01-27 14:57:51 +01007283 if (!unres || !(*unres)) {
7284 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007285 }
7286
Michal Vasko44ab1462017-05-18 13:18:36 +02007287 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007288
7289 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007290 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007291 if ((*unres)->type[i] != UNRES_RESOLVED) {
7292 unresolved++;
7293 }
7294 continue;
7295 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007296
7297 /* free heap memory for the specific item */
7298 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007299 }
7300
Michal Vaskoede9c472016-06-07 09:38:15 +02007301 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007302 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007303 free((*unres)->item);
7304 free((*unres)->type);
7305 free((*unres)->str_snode);
7306 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007307 free((*unres));
7308 (*unres) = NULL;
7309 }
Michal Vasko88c29542015-11-27 14:57:53 +01007310}
7311
Michal Vaskoff690e72017-08-03 14:25:07 +02007312/* check whether instance-identifier points outside its data subtree (for operation it is any node
7313 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007314static int
7315check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7316{
Michal Vaskoff690e72017-08-03 14:25:07 +02007317 const struct lys_node *op_node, *first_node;
Michal Vasko53b7da02018-02-13 15:28:42 +01007318 enum int_log_opts prev_ilo;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007319 char *buf;
Michal Vasko53b7da02018-02-13 15:28:42 +01007320 int ret = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007321
Radek Krejci034cb102017-08-01 15:45:13 +02007322 if (!json_instid || !json_instid[0]) {
7323 /* no/empty value */
7324 return 0;
7325 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007326
7327 for (op_node = lys_parent(sleaf);
7328 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7329 op_node = lys_parent(op_node));
7330
7331 if (op_node && lys_parent(op_node)) {
7332 /* nested operation - any absolute path is external */
7333 return 1;
7334 }
7335
7336 /* get the first node from the instid */
7337 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7338 if (!buf) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007339 /* so that we do not have to bother with logging, say it is not external */
7340 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007341 }
7342
Michal Vaskoff690e72017-08-03 14:25:07 +02007343 /* find the first schema node, do not log */
Michal Vasko53b7da02018-02-13 15:28:42 +01007344 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoff690e72017-08-03 14:25:07 +02007345 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
Michal Vasko53b7da02018-02-13 15:28:42 +01007346 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007347
Michal Vasko53b7da02018-02-13 15:28:42 +01007348 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007349 if (!first_node) {
7350 /* unknown path, say it is not external */
Michal Vaskoff690e72017-08-03 14:25:07 +02007351 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007352 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007353
7354 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7355
Michal Vaskoff690e72017-08-03 14:25:07 +02007356 if (op_node && (op_node != first_node)) {
7357 /* it is a top-level operation, so we're good if it points somewhere inside it */
7358 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007359 }
7360
7361 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7362 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007363 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007364}
7365
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007366/**
7367 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7368 *
7369 * @param[in] data Data node where the path is used
7370 * @param[in] path Instance-identifier node value.
7371 * @param[in,out] ret Resolved instance or NULL.
7372 *
7373 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7374 */
7375static int
7376resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7377{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007378 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007379 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007380 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007381 struct lyd_node *root, *node;
Radek Krejcidaa547a2017-09-22 15:56:27 +02007382 const char *model = NULL, *name;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007383 char *str;
7384 int mod_len, name_len, has_predicate;
7385 struct unres_data node_match;
7386
7387 memset(&node_match, 0, sizeof node_match);
7388 *ret = NULL;
7389
7390 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007391 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007392 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007393 if (root->prev) {
7394 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007395 }
7396
7397 /* search for the instance node */
7398 while (path[i]) {
7399 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7400 if (j <= 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007401 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007402 goto error;
7403 }
7404 i += j;
7405
Michal Vasko1b6ca962017-08-03 14:23:09 +02007406 if (model) {
7407 str = strndup(model, mod_len);
7408 if (!str) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007409 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007410 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007411 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02007412 mod = ly_ctx_get_module(ctx, str, NULL, 1);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007413 if (ctx->data_clb) {
7414 if (!mod) {
7415 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7416 } else if (!mod->implemented) {
7417 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7418 }
7419 }
7420 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007421
Michal Vasko1b6ca962017-08-03 14:23:09 +02007422 if (!mod || !mod->implemented || mod->disabled) {
7423 break;
7424 }
7425 } else if (!prev_mod) {
7426 /* first iteration and we are missing module name */
Michal Vasko53b7da02018-02-13 15:28:42 +01007427 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_NONE, NULL, name_len, name);
7428 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instane-identifier is missing prefix in the first node.");
Michal Vasko1b6ca962017-08-03 14:23:09 +02007429 goto error;
7430 } else {
7431 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007432 }
7433
Radek Krejci2c822ed2017-08-03 14:23:36 +02007434 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007435 /* no instance exists */
7436 break;
7437 }
7438
7439 if (has_predicate) {
7440 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcidaa547a2017-09-22 15:56:27 +02007441 parsed = j = 0;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007442 /* index of the current node (for lists with position predicates) */
7443 cur_idx = 1;
7444 while (j < (signed)node_match.count) {
7445 node = node_match.node[j];
7446 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7447 if (parsed < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007448 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007449 goto error;
7450 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007451
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007452 if (!node) {
7453 /* current node does not satisfy the predicate */
7454 unres_data_del(&node_match, j);
7455 } else {
7456 ++j;
7457 }
7458 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007459 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007460
7461 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007462 } else if (node_match.count) {
7463 /* check that we are not addressing lists */
7464 for (j = 0; (unsigned)j < node_match.count; ++j) {
7465 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7466 unres_data_del(&node_match, j--);
7467 }
7468 }
7469 if (!node_match.count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007470 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007471 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007472 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007473
7474 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007475 }
7476
7477 if (!node_match.count) {
7478 /* no instance exists */
7479 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007480 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007481 return EXIT_FAILURE;
7482 }
7483 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7484 return EXIT_SUCCESS;
7485 } else if (node_match.count > 1) {
7486 /* instance identifier must resolve to a single node */
Michal Vasko53b7da02018-02-13 15:28:42 +01007487 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007488 goto error;
7489 } else {
7490 /* we have required result, remember it and cleanup */
7491 *ret = node_match.node[0];
7492 free(node_match.node);
7493 return EXIT_SUCCESS;
7494 }
7495
7496error:
7497 /* cleanup */
7498 free(node_match.node);
7499 return -1;
7500}
7501
7502static int
7503resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007504{
Michal Vaskoca16cb32017-07-10 11:50:33 +02007505 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007506 uint32_t i;
7507
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007508 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007509
Michal Vaskoca16cb32017-07-10 11:50:33 +02007510 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007511 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vaskoca16cb32017-07-10 11:50:33 +02007512 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007513 return -1;
7514 }
7515
Michal Vaskoca16cb32017-07-10 11:50:33 +02007516 for (i = 0; i < set->number; ++i) {
7517 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7518 continue;
7519 }
7520
Radek Krejci1899d6a2016-11-03 13:48:07 +01007521 /* not that the value is already in canonical form since the parsers does the conversion,
7522 * so we can simply compare just the values */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007523 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 +01007524 /* we have the match */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007525 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007526 break;
7527 }
7528 }
7529
Michal Vaskoca16cb32017-07-10 11:50:33 +02007530 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007531
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007532 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007533 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007534 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007535 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007536 return EXIT_FAILURE;
7537 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007538 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 +02007539 }
7540 }
7541
7542 return EXIT_SUCCESS;
7543}
7544
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007545/* 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 +01007546int
7547resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7548 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007549{
Michal Vasko53b7da02018-02-13 15:28:42 +01007550 struct ly_ctx *ctx = leaf->schema->module->ctx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007551 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007552 struct lyd_node *ret;
Michal Vasko53b7da02018-02-13 15:28:42 +01007553 enum int_log_opts prev_ilo;
7554 int found, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007555 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007556
7557 assert(type->base == LY_TYPE_UNION);
7558
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007559 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7560 /* either NULL or instid previously converted to JSON */
7561 json_val = leaf->value.string;
7562 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007563
Michal Vaskofd6c6502017-01-06 12:15:41 +01007564 if (store) {
7565 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7566 free(leaf->value.bit);
7567 }
7568 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007569 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007570
7571 /* turn logging off, we are going to try to validate the value with all the types in order */
Michal Vasko53b7da02018-02-13 15:28:42 +01007572 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007573
7574 t = NULL;
7575 found = 0;
7576 while ((t = lyp_get_next_union_type(type, t, &found))) {
7577 found = 0;
7578
7579 switch (t->base) {
7580 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007581 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7582 req_inst = -1;
7583 } else {
7584 req_inst = t->info.lref.req;
7585 }
7586
7587 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007588 if (store) {
7589 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7590 /* valid resolved */
7591 leaf->value.leafref = ret;
7592 leaf->value_type = LY_TYPE_LEAFREF;
7593 } else {
7594 /* valid unresolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01007595 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko31a2d322018-01-12 13:36:12 +01007596 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007597 return -1;
7598 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007599 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007600 }
7601 }
7602
7603 success = 1;
7604 }
7605 break;
7606 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007607 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7608 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7609 req_inst = -1;
7610 } else {
7611 req_inst = t->info.inst.req;
7612 }
7613
Michal Vaskod3a03112017-01-23 09:56:02 +01007614 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007615 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007616 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007617 /* valid resolved */
7618 leaf->value.instance = ret;
7619 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007620
Michal Vaskofd6c6502017-01-06 12:15:41 +01007621 if (json_val) {
7622 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7623 leaf->value_str = json_val;
7624 json_val = NULL;
7625 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007626 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007627 /* valid unresolved */
7628 if (json_val) {
7629 /* put the JSON val back */
7630 leaf->value.string = json_val;
7631 json_val = NULL;
7632 } else {
7633 leaf->value.instance = NULL;
7634 }
7635 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007636 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007637 }
7638
7639 success = 1;
7640 }
7641 break;
7642 default:
Michal Vasko31a2d322018-01-12 13:36:12 +01007643 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007644 success = 1;
7645 }
7646 break;
7647 }
7648
7649 if (success) {
7650 break;
7651 }
7652
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007653 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007654 if (store) {
7655 if (t->base == LY_TYPE_BITS) {
7656 free(leaf->value.bit);
7657 }
7658 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007659 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007660 }
7661
7662 /* turn logging back on */
Michal Vasko53b7da02018-02-13 15:28:42 +01007663 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007664
7665 if (json_val) {
7666 if (!success) {
7667 /* put the value back for now */
7668 assert(leaf->value_type == LY_TYPE_UNION);
7669 leaf->value.string = json_val;
7670 } else {
7671 /* value was ultimately useless, but we could not have known */
7672 lydict_remove(leaf->schema->module->ctx, json_val);
7673 }
7674 }
7675
Michal Vaskofd6c6502017-01-06 12:15:41 +01007676 if (success) {
7677 if (resolved_type) {
7678 *resolved_type = t;
7679 }
7680 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007681 /* not found and it is required */
Michal Vasko53b7da02018-02-13 15:28:42 +01007682 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007683 return EXIT_FAILURE;
7684 }
7685
7686 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007687
Radek Krejci9b6aad22016-09-20 15:55:51 +02007688}
7689
Michal Vasko8bcdf292015-08-19 14:04:43 +02007690/**
7691 * @brief Resolve a single unres data item. Logs directly.
7692 *
Michal Vaskocf024702015-10-08 15:01:42 +02007693 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007694 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007695 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007696 *
7697 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7698 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007699int
Michal Vasko0b963112017-08-11 12:45:36 +02007700resolve_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 +02007701{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007702 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007703 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007704 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007705 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007706
Michal Vasko83a6c462015-10-08 16:43:53 +02007707 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007708 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007709
Michal Vaskocf024702015-10-08 15:01:42 +02007710 switch (type) {
7711 case UNRES_LEAFREF:
7712 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007713 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007714 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7715 req_inst = -1;
7716 } else {
7717 req_inst = sleaf->type.info.lref.req;
7718 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007719 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7720 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007721 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007722 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007723 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7724 free(leaf->value.bit);
7725 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007726 leaf->value.leafref = ret;
7727 leaf->value_type = LY_TYPE_LEAFREF;
7728 } else {
7729 /* valid unresolved */
7730 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Michal Vasko31a2d322018-01-12 13:36:12 +01007731 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007732 return -1;
7733 }
7734 }
7735 }
7736 leaf->validity &= ~LYD_VAL_LEAFREF;
7737 } else {
7738 return rc;
7739 }
7740 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007741
Michal Vaskocf024702015-10-08 15:01:42 +02007742 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007743 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007744 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7745 if (ext_dep == -1) {
7746 return -1;
7747 }
7748
7749 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7750 req_inst = -1;
7751 } else {
7752 req_inst = sleaf->type.info.inst.req;
7753 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007754 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7755 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007756 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007757 /* valid resolved */
7758 leaf->value.instance = ret;
7759 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007760 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007761 /* valid unresolved */
7762 leaf->value.instance = NULL;
7763 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007764 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007765 } else {
7766 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007767 }
Michal Vaskocf024702015-10-08 15:01:42 +02007768 break;
7769
Radek Krejci7de36cf2016-09-12 16:18:50 +02007770 case UNRES_UNION:
7771 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007772 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007773
Michal Vaskocf024702015-10-08 15:01:42 +02007774 case UNRES_WHEN:
Michal Vasko0b963112017-08-11 12:45:36 +02007775 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007776 return rc;
7777 }
7778 break;
7779
Michal Vaskobf19d252015-10-08 15:39:17 +02007780 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007781 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007782 return rc;
7783 }
7784 break;
7785
7786 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007787 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007788 return rc;
7789 }
7790 break;
7791
Michal Vaskocf024702015-10-08 15:01:42 +02007792 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007793 LOGINT(NULL);
Michal Vasko8bcdf292015-08-19 14:04:43 +02007794 return -1;
7795 }
7796
7797 return EXIT_SUCCESS;
7798}
7799
7800/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007801 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007802 *
7803 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007804 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007805 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007806 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007807 */
7808int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007809unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007810{
Radek Krejci03b71f72016-03-16 11:10:09 +01007811 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007812 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007813 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007814
Radek Krejci03b71f72016-03-16 11:10:09 +01007815 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007816 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01007817 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007818 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007819 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007820 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007821 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007822
Radek Krejci0b7704f2016-03-18 12:16:14 +01007823 if (type == UNRES_WHEN) {
7824 /* remove previous result */
7825 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007826 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007827
Michal Vasko53b7da02018-02-13 15:28:42 +01007828 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007829}
7830
7831/**
7832 * @brief Resolve every unres data item in the structure. Logs directly.
7833 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007834 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7835 * unresolved leafrefs/instids are accepted).
7836 *
7837 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7838 *
Michal Vasko53b7da02018-02-13 15:28:42 +01007839 * @param[in] ctx Context used.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007840 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007841 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7842 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007843 *
7844 * @return EXIT_SUCCESS on success, -1 on error.
7845 */
7846int
Michal Vasko53b7da02018-02-13 15:28:42 +01007847resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007848{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007849 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007850 int rc, progress, ignore_fail;
Michal Vasko53b7da02018-02-13 15:28:42 +01007851 enum int_log_opts prev_ilo;
7852 struct ly_err_item *prev_eitem;
7853 LY_ERR prev_ly_errno;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007854 struct lyd_node *parent;
Michal Vasko0b963112017-08-11 12:45:36 +02007855 struct lys_when *when;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007856
Radek Krejci082c84f2016-10-17 16:33:06 +02007857 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007858 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007859
7860 if (!unres->count) {
7861 return EXIT_SUCCESS;
7862 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007863
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007864 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 +01007865 ignore_fail = 1;
7866 } else if (options & LYD_OPT_NOEXTDEPS) {
7867 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007868 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007869 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007870 }
7871
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007872 LOGVRB("Resolving unresolved data nodes and their constraints...");
Michal Vasko53b7da02018-02-13 15:28:42 +01007873 /* remember logging state */
7874 prev_ly_errno = ly_errno;
7875 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Radek Krejci010e54b2016-03-15 09:40:34 +01007876
Radek Krejci0b7704f2016-03-18 12:16:14 +01007877 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007878 first = 1;
7879 stmt_count = 0;
7880 resolved = 0;
7881 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007882 do {
Michal Vasko53b7da02018-02-13 15:28:42 +01007883 ly_err_free_next(ctx, prev_eitem);
Radek Krejci010e54b2016-03-15 09:40:34 +01007884 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007885 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007886 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007887 continue;
7888 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007889 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007890 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007891 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007892 }
7893
7894 /* resolve when condition only when all parent when conditions are already resolved */
7895 for (parent = unres->node[i]->parent;
7896 parent && LYD_WHEN_DONE(parent->when_status);
7897 parent = parent->parent) {
7898 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7899 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02007900 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01007901 */
7902 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7903 unres->type[i] = UNRES_RESOLVED;
7904 resolved++;
7905 break;
7906 }
7907 }
7908 if (parent) {
7909 continue;
7910 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007911
Michal Vasko0b963112017-08-11 12:45:36 +02007912 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01007913 if (!rc) {
Michal Vasko0b963112017-08-11 12:45:36 +02007914 /* finish with error/delete the node only if when was false, an external dependency was not required,
7915 * or it was not provided (the flag would not be passed down otherwise, checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02007916 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vasko0b963112017-08-11 12:45:36 +02007917 && (!(when->flags & LYS_XPATH_DEP) || !(options & LYD_OPT_NOEXTDEPS))) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007918 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007919 /* false when condition */
Michal Vasko53b7da02018-02-13 15:28:42 +01007920 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007921 } /* follows else */
7922
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007923 /* auto-delete */
Michal Vasko53b7da02018-02-13 15:28:42 +01007924 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007925
Radek Krejci0c0086a2016-03-24 15:20:28 +01007926 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7927 /* if it has parent non-presence containers that would be empty, we should actually
7928 * remove the container
7929 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007930 for (parent = unres->node[i];
7931 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7932 parent = parent->parent) {
7933 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7934 /* presence container */
7935 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007936 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007937 if (parent->next || parent->prev != parent) {
7938 /* non empty (the child we are in and we are going to remove is not the only child) */
7939 break;
7940 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007941 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007942 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007943
Radek Krejci0c0086a2016-03-24 15:20:28 +01007944 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007945 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007946 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007947
Radek Krejci0b7704f2016-03-18 12:16:14 +01007948 lyd_unlink(unres->node[i]);
7949 unres->type[i] = UNRES_DELETE;
7950 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007951
7952 /* update the rest of unres items */
7953 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007954 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007955 continue;
7956 }
7957
7958 /* test if the node is in subtree to be deleted */
7959 for (parent = unres->node[j]; parent; parent = parent->parent) {
7960 if (parent == unres->node[i]) {
7961 /* yes, it is */
7962 unres->type[j] = UNRES_RESOLVED;
7963 resolved++;
7964 break;
7965 }
7966 }
7967 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007968 } else {
7969 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007970 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007971 ly_err_free_next(ctx, prev_eitem);
Radek Krejci010e54b2016-03-15 09:40:34 +01007972 resolved++;
7973 progress = 1;
7974 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007975 goto error;
Radek Krejci2467a492016-10-24 15:16:59 +02007976 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007977 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007978 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007979 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007980
Radek Krejci0b7704f2016-03-18 12:16:14 +01007981 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007982 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007983 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007984 }
7985
7986 for (i = 0; del_items && i < unres->count; i++) {
7987 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7988 if (unres->type[i] != UNRES_DELETE) {
7989 continue;
7990 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007991 if (!unres->node[i]) {
7992 unres->type[i] = UNRES_RESOLVED;
7993 del_items--;
7994 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007995 }
7996
7997 /* really remove the complete subtree */
7998 lyd_free(unres->node[i]);
7999 unres->type[i] = UNRES_RESOLVED;
8000 del_items--;
8001 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008002
8003 /* now leafrefs */
8004 first = 1;
8005 stmt_count = 0;
8006 resolved = 0;
8007 do {
8008 progress = 0;
8009 for (i = 0; i < unres->count; i++) {
8010 if (unres->type[i] != UNRES_LEAFREF) {
8011 continue;
8012 }
8013 if (first) {
8014 /* count leafref nodes in unres list */
8015 stmt_count++;
8016 }
8017
Michal Vasko0b963112017-08-11 12:45:36 +02008018 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008019 if (!rc) {
8020 unres->type[i] = UNRES_RESOLVED;
Michal Vasko53b7da02018-02-13 15:28:42 +01008021 ly_err_free_next(ctx, prev_eitem);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008022 resolved++;
8023 progress = 1;
8024 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008025 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008026 } /* else forward reference */
8027 }
8028 first = 0;
8029 } while (progress && resolved < stmt_count);
8030
8031 /* do we have some unresolved leafrefs? */
8032 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008033 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008034 }
8035
Michal Vasko53b7da02018-02-13 15:28:42 +01008036 /* log normally now, throw away irrelevant errors */
8037 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8038 ly_errno = prev_ly_errno;
Radek Krejci010e54b2016-03-15 09:40:34 +01008039
8040 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008041 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008042 if (unres->type[i] == UNRES_RESOLVED) {
8043 continue;
8044 }
Radek Krejci082c84f2016-10-17 16:33:06 +02008045 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01008046
Michal Vasko0b963112017-08-11 12:45:36 +02008047 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008048 if (rc) {
8049 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008050 return -1;
8051 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008052
8053 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008054 }
8055
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008056 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01008057 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008058 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01008059
8060error:
8061 /* print all the new errors */
8062 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8063 /* do not restore ly_errno, it was udpated properly */
8064 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008065}