blob: 790c86d1c5eeb97bd460d72cf61643f5e268d952 [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"
Michal Vasko6c810702018-03-14 16:23:21 +010030#include "hash_table.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.
PavolVicanb28bbff2018-02-21 00:44:02 +0100172 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
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{
PavolVican195cf392018-02-23 13:24:45 +0100181 int parsed = 0, ret, all_desc_local = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200182
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));
Michal Vasko50576712017-07-28 12:28:33 +0200186
Michal Vasko723e50c2015-10-20 15:20:29 +0200187 if (mod_name) {
188 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200189 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200190 }
191 if (name) {
192 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200193 *nam_len = 0;
194 }
195
Michal Vasko50576712017-07-28 12:28:33 +0200196 if (extended) {
197 /* try to parse only the extended expressions */
198 if (id[parsed] == '/') {
PavolVican195cf392018-02-23 13:24:45 +0100199 if (all_desc) {
200 *all_desc = 1;
201 }
202 all_desc_local = 1;
Michal Vasko50576712017-07-28 12:28:33 +0200203 } else {
PavolVican195cf392018-02-23 13:24:45 +0100204 if (all_desc) {
205 *all_desc = 0;
206 }
Michal Vasko50576712017-07-28 12:28:33 +0200207 }
208
209 /* is there a prefix? */
PavolVican195cf392018-02-23 13:24:45 +0100210 ret = parse_identifier(id + all_desc_local);
Michal Vasko50576712017-07-28 12:28:33 +0200211 if (ret > 0) {
PavolVican195cf392018-02-23 13:24:45 +0100212 if (id[all_desc_local + ret] != ':') {
Michal Vasko50576712017-07-28 12:28:33 +0200213 /* this is not a prefix, so not an extended id */
214 goto standard_id;
215 }
216
217 if (mod_name) {
PavolVican195cf392018-02-23 13:24:45 +0100218 *mod_name = id + all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200219 *mod_name_len = ret;
220 }
221
222 /* "/" and ":" */
PavolVican195cf392018-02-23 13:24:45 +0100223 ret += all_desc_local + 1;
Michal Vasko50576712017-07-28 12:28:33 +0200224 } else {
PavolVican195cf392018-02-23 13:24:45 +0100225 ret = all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200226 }
227
228 /* parse either "*" or "." */
PavolVicanb28bbff2018-02-21 00:44:02 +0100229 if (*(id + ret) == '*') {
Michal Vasko50576712017-07-28 12:28:33 +0200230 if (name) {
231 *name = id + ret;
232 *nam_len = 1;
233 }
234 ++ret;
235
236 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100237 } else if (*(id + ret) == '.') {
PavolVican195cf392018-02-23 13:24:45 +0100238 if (!all_desc_local) {
Michal Vasko50576712017-07-28 12:28:33 +0200239 /* /. is redundant expression, we do not accept it */
240 return -ret;
241 }
242
243 if (name) {
244 *name = id + ret;
245 *nam_len = 1;
246 }
247 ++ret;
248
249 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100250 } else if (*(id + ret) == '#') {
PavolVican195cf392018-02-23 13:24:45 +0100251 if (all_desc_local || !ret) {
PavolVicanb28bbff2018-02-21 00:44:02 +0100252 /* no prefix */
253 return 0;
254 }
255 parsed = ret + 1;
256 if ((ret = parse_identifier(id + parsed)) < 1) {
257 return -parsed + ret;
258 }
259 *name = id + parsed - 1;
260 *nam_len = ret + 1;
261 return parsed + ret;
Michal Vasko50576712017-07-28 12:28:33 +0200262 }
263 /* else a standard id, parse it all again */
264 }
265
266standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200267 if ((ret = parse_identifier(id)) < 1) {
268 return ret;
269 }
270
Michal Vasko723e50c2015-10-20 15:20:29 +0200271 if (mod_name) {
272 *mod_name = id;
Michal Vasko723e50c2015-10-20 15:20:29 +0200273 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200274 }
275
276 parsed += ret;
277 id += ret;
278
279 /* there is prefix */
280 if (id[0] == ':') {
281 ++parsed;
282 ++id;
283
284 /* there isn't */
285 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200286 if (name && mod_name) {
287 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200288 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200289 if (mod_name) {
290 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200291 }
292
Michal Vasko723e50c2015-10-20 15:20:29 +0200293 if (nam_len && mod_name_len) {
294 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200295 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200296 if (mod_name_len) {
297 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200298 }
299
300 return parsed;
301 }
302
303 /* identifier (node name) */
304 if ((ret = parse_identifier(id)) < 1) {
305 return -parsed+ret;
306 }
307
308 if (name) {
309 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200310 *nam_len = ret;
311 }
312
313 return parsed+ret;
314}
315
316/**
317 * @brief Parse a path-predicate (leafref).
318 *
319 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
320 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
321 *
Michal Vaskobb211122015-08-19 14:03:11 +0200322 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200323 * @param[out] prefix Points to the prefix, NULL if there is not any.
324 * @param[out] pref_len Length of the prefix, 0 if there is not any.
325 * @param[out] name Points to the node name.
326 * @param[out] nam_len Length of the node name.
327 * @param[out] path_key_expr Points to the path-key-expr.
328 * @param[out] pke_len Length of the path-key-expr.
329 * @param[out] has_predicate Flag to mark whether there is another predicate following.
330 *
331 * @return Number of characters successfully parsed,
332 * positive on success, negative on failure.
333 */
334static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200335parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
336 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200337{
338 const char *ptr;
339 int parsed = 0, ret;
340
341 assert(id);
342 if (prefix) {
343 *prefix = NULL;
344 }
345 if (pref_len) {
346 *pref_len = 0;
347 }
348 if (name) {
349 *name = NULL;
350 }
351 if (nam_len) {
352 *nam_len = 0;
353 }
354 if (path_key_expr) {
355 *path_key_expr = NULL;
356 }
357 if (pke_len) {
358 *pke_len = 0;
359 }
360 if (has_predicate) {
361 *has_predicate = 0;
362 }
363
364 if (id[0] != '[') {
365 return -parsed;
366 }
367
368 ++parsed;
369 ++id;
370
371 while (isspace(id[0])) {
372 ++parsed;
373 ++id;
374 }
375
Michal Vasko50576712017-07-28 12:28:33 +0200376 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200377 return -parsed+ret;
378 }
379
380 parsed += ret;
381 id += ret;
382
383 while (isspace(id[0])) {
384 ++parsed;
385 ++id;
386 }
387
388 if (id[0] != '=') {
389 return -parsed;
390 }
391
392 ++parsed;
393 ++id;
394
395 while (isspace(id[0])) {
396 ++parsed;
397 ++id;
398 }
399
400 if ((ptr = strchr(id, ']')) == NULL) {
401 return -parsed;
402 }
403
404 --ptr;
405 while (isspace(ptr[0])) {
406 --ptr;
407 }
408 ++ptr;
409
410 ret = ptr-id;
411 if (path_key_expr) {
412 *path_key_expr = id;
413 }
414 if (pke_len) {
415 *pke_len = ret;
416 }
417
418 parsed += ret;
419 id += ret;
420
421 while (isspace(id[0])) {
422 ++parsed;
423 ++id;
424 }
425
426 assert(id[0] == ']');
427
428 if (id[1] == '[') {
429 *has_predicate = 1;
430 }
431
432 return parsed+1;
433}
434
435/**
436 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
437 * the ".." and the first node-identifier, other calls parse a single
438 * node-identifier each.
439 *
440 * path-key-expr = current-function-invocation *WSP "/" *WSP
441 * rel-path-keyexpr
442 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
443 * *(node-identifier *WSP "/" *WSP)
444 * node-identifier
445 *
Michal Vaskobb211122015-08-19 14:03:11 +0200446 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200447 * @param[out] prefix Points to the prefix, NULL if there is not any.
448 * @param[out] pref_len Length of the prefix, 0 if there is not any.
449 * @param[out] name Points to the node name.
450 * @param[out] nam_len Length of the node name.
451 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
452 * must not be changed between consecutive calls.
453 * @return Number of characters successfully parsed,
454 * positive on success, negative on failure.
455 */
456static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200457parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
458 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200459{
460 int parsed = 0, ret, par_times = 0;
461
462 assert(id);
463 assert(parent_times);
464 if (prefix) {
465 *prefix = NULL;
466 }
467 if (pref_len) {
468 *pref_len = 0;
469 }
470 if (name) {
471 *name = NULL;
472 }
473 if (nam_len) {
474 *nam_len = 0;
475 }
476
477 if (!*parent_times) {
478 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
479 if (strncmp(id, "current()", 9)) {
480 return -parsed;
481 }
482
483 parsed += 9;
484 id += 9;
485
486 while (isspace(id[0])) {
487 ++parsed;
488 ++id;
489 }
490
491 if (id[0] != '/') {
492 return -parsed;
493 }
494
495 ++parsed;
496 ++id;
497
498 while (isspace(id[0])) {
499 ++parsed;
500 ++id;
501 }
502
503 /* rel-path-keyexpr */
504 if (strncmp(id, "..", 2)) {
505 return -parsed;
506 }
507 ++par_times;
508
509 parsed += 2;
510 id += 2;
511
512 while (isspace(id[0])) {
513 ++parsed;
514 ++id;
515 }
516 }
517
518 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
519 *
520 * first parent reference with whitespaces already parsed
521 */
522 if (id[0] != '/') {
523 return -parsed;
524 }
525
526 ++parsed;
527 ++id;
528
529 while (isspace(id[0])) {
530 ++parsed;
531 ++id;
532 }
533
534 while (!strncmp(id, "..", 2) && !*parent_times) {
535 ++par_times;
536
537 parsed += 2;
538 id += 2;
539
540 while (isspace(id[0])) {
541 ++parsed;
542 ++id;
543 }
544
545 if (id[0] != '/') {
546 return -parsed;
547 }
548
549 ++parsed;
550 ++id;
551
552 while (isspace(id[0])) {
553 ++parsed;
554 ++id;
555 }
556 }
557
558 if (!*parent_times) {
559 *parent_times = par_times;
560 }
561
562 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200563 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
564 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200565 }
566
567 parsed += ret;
568 id += ret;
569
570 return parsed;
571}
572
573/**
574 * @brief Parse path-arg (leafref).
575 *
576 * path-arg = absolute-path / relative-path
577 * absolute-path = 1*("/" (node-identifier *path-predicate))
578 * relative-path = 1*(".." "/") descendant-path
579 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200580 * @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 +0200581 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200582 * @param[out] prefix Points to the prefix, NULL if there is not any.
583 * @param[out] pref_len Length of the prefix, 0 if there is not any.
584 * @param[out] name Points to the node name.
585 * @param[out] nam_len Length of the node name.
586 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
587 * must not be changed between consecutive calls. -1 if the
588 * path is relative.
589 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
590 *
591 * @return Number of characters successfully parsed,
592 * positive on success, negative on failure.
593 */
594static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200595parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200596 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597{
598 int parsed = 0, ret, par_times = 0;
599
600 assert(id);
601 assert(parent_times);
602 if (prefix) {
603 *prefix = NULL;
604 }
605 if (pref_len) {
606 *pref_len = 0;
607 }
608 if (name) {
609 *name = NULL;
610 }
611 if (nam_len) {
612 *nam_len = 0;
613 }
614 if (has_predicate) {
615 *has_predicate = 0;
616 }
617
618 if (!*parent_times && !strncmp(id, "..", 2)) {
619 ++par_times;
620
621 parsed += 2;
622 id += 2;
623
624 while (!strncmp(id, "/..", 3)) {
625 ++par_times;
626
627 parsed += 3;
628 id += 3;
629 }
630 }
631
632 if (!*parent_times) {
633 if (par_times) {
634 *parent_times = par_times;
635 } else {
636 *parent_times = -1;
637 }
638 }
639
640 if (id[0] != '/') {
641 return -parsed;
642 }
643
644 /* skip '/' */
645 ++parsed;
646 ++id;
647
648 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200649 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
650 return -parsed - ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200651 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200652 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200653 /* actually we always need prefix even it is not specified */
654 *prefix = lys_main_module(mod)->name;
655 *pref_len = strlen(*prefix);
656 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200657
658 parsed += ret;
659 id += ret;
660
661 /* there is no predicate */
662 if ((id[0] == '/') || !id[0]) {
663 return parsed;
664 } else if (id[0] != '[') {
665 return -parsed;
666 }
667
668 if (has_predicate) {
669 *has_predicate = 1;
670 }
671
672 return parsed;
673}
674
675/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200676 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200677 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200678 *
679 * instance-identifier = 1*("/" (node-identifier *predicate))
680 *
Michal Vaskobb211122015-08-19 14:03:11 +0200681 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200682 * @param[out] model Points to the model name.
683 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200684 * @param[out] name Points to the node name.
685 * @param[out] nam_len Length of the node name.
686 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
687 *
688 * @return Number of characters successfully parsed,
689 * positive on success, negative on failure.
690 */
691static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200692parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
693 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200694{
695 int parsed = 0, ret;
696
Michal Vasko1b6ca962017-08-03 14:23:09 +0200697 assert(id && model && mod_len && name && nam_len);
698
Radek Krejci6dc53a22015-08-17 13:27:59 +0200699 if (has_predicate) {
700 *has_predicate = 0;
701 }
702
703 if (id[0] != '/') {
704 return -parsed;
705 }
706
707 ++parsed;
708 ++id;
709
Michal Vaskob2f40be2016-09-08 16:03:48 +0200710 if ((ret = parse_identifier(id)) < 1) {
711 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200712 }
713
Michal Vaskob2f40be2016-09-08 16:03:48 +0200714 *name = id;
715 *nam_len = ret;
716
717 parsed += ret;
718 id += ret;
719
Michal Vasko1b6ca962017-08-03 14:23:09 +0200720 if (id[0] == ':') {
721 /* we have prefix */
722 *model = *name;
723 *mod_len = *nam_len;
724
725 ++parsed;
726 ++id;
727
728 if ((ret = parse_identifier(id)) < 1) {
729 return ret;
730 }
731
732 *name = id;
733 *nam_len = ret;
734
735 parsed += ret;
736 id += ret;
737 }
738
Radek Krejci4967cb62016-09-14 16:40:28 +0200739 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200740 *has_predicate = 1;
741 }
742
743 return parsed;
744}
745
746/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200747 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200748 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200749 *
750 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
751 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
752 * ((DQUOTE string DQUOTE) /
753 * (SQUOTE string SQUOTE))
754 * pos = non-negative-integer-value
755 *
Michal Vaskobb211122015-08-19 14:03:11 +0200756 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200757 * @param[out] model Points to the model name.
758 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200759 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
760 * @param[out] nam_len Length of the node name.
761 * @param[out] value Value the node-identifier must have (string from the grammar),
762 * NULL if there is not any.
763 * @param[out] val_len Length of the value, 0 if there is not any.
764 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
765 *
766 * @return Number of characters successfully parsed,
767 * positive on success, negative on failure.
768 */
769static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200770parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
771 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200772{
773 const char *ptr;
774 int parsed = 0, ret;
775 char quote;
776
777 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200778 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200779 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200780 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200781 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200782 }
783 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200784 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200785 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200786 *nam_len = 0;
787 }
788 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200789 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200790 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200791 *val_len = 0;
792 }
793 if (has_predicate) {
794 *has_predicate = 0;
795 }
796
797 if (id[0] != '[') {
798 return -parsed;
799 }
800
801 ++parsed;
802 ++id;
803
804 while (isspace(id[0])) {
805 ++parsed;
806 ++id;
807 }
808
809 /* pos */
810 if (isdigit(id[0])) {
811 if (name) {
812 *name = id;
813 }
814
815 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200816 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200817 }
818
819 while (isdigit(id[0])) {
820 ++parsed;
821 ++id;
822 }
823
824 if (nam_len) {
825 *nam_len = id-(*name);
826 }
827
Michal Vaskof2f28a12016-09-09 12:43:06 +0200828 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200829 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200830 if (id[0] == '.') {
831 if (name) {
832 *name = id;
833 }
834 if (nam_len) {
835 *nam_len = 1;
836 }
837
838 ++parsed;
839 ++id;
840
841 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200842 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200843 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200844 }
845
846 parsed += ret;
847 id += ret;
848 }
849
850 while (isspace(id[0])) {
851 ++parsed;
852 ++id;
853 }
854
855 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200856 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200857 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200858
Radek Krejci6dc53a22015-08-17 13:27:59 +0200859 ++parsed;
860 ++id;
861
Michal Vaskof2f28a12016-09-09 12:43:06 +0200862 while (isspace(id[0])) {
863 ++parsed;
864 ++id;
865 }
866
867 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
868 if ((id[0] == '\"') || (id[0] == '\'')) {
869 quote = id[0];
870
871 ++parsed;
872 ++id;
873
874 if ((ptr = strchr(id, quote)) == NULL) {
875 return -parsed;
876 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200877 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200878
879 if (value) {
880 *value = id;
881 }
882 if (val_len) {
883 *val_len = ret;
884 }
885
Michal Vasko1b6ca962017-08-03 14:23:09 +0200886 parsed += ret + 1;
887 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200888 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200889 return -parsed;
890 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200891 }
892
893 while (isspace(id[0])) {
894 ++parsed;
895 ++id;
896 }
897
898 if (id[0] != ']') {
899 return -parsed;
900 }
901
902 ++parsed;
903 ++id;
904
905 if ((id[0] == '[') && has_predicate) {
906 *has_predicate = 1;
907 }
908
909 return parsed;
910}
911
912/**
913 * @brief Parse schema-nodeid.
914 *
915 * schema-nodeid = absolute-schema-nodeid /
916 * descendant-schema-nodeid
917 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200918 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200919 * node-identifier
920 * absolute-schema-nodeid
921 *
Michal Vaskobb211122015-08-19 14:03:11 +0200922 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200923 * @param[out] mod_name Points to the module name, NULL if there is not any.
924 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200925 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200926 * @param[out] nam_len Length of the node name.
927 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
928 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100929 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
930 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200931 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200932 *
933 * @return Number of characters successfully parsed,
934 * positive on success, negative on failure.
935 */
Michal Vasko22448d32016-03-16 13:17:29 +0100936int
Michal Vasko723e50c2015-10-20 15:20:29 +0200937parse_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 +0200938 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200939{
940 int parsed = 0, ret;
941
942 assert(id);
943 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200944
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100945 if (has_predicate) {
946 *has_predicate = 0;
947 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200948
949 if (id[0] != '/') {
950 if (*is_relative != -1) {
951 return -parsed;
952 } else {
953 *is_relative = 1;
954 }
Michal Vasko48935352016-03-29 11:52:36 +0200955 if (!strncmp(id, "./", 2)) {
956 parsed += 2;
957 id += 2;
958 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200959 } else {
960 if (*is_relative == -1) {
961 *is_relative = 0;
962 }
963 ++parsed;
964 ++id;
965 }
966
Michal Vasko50576712017-07-28 12:28:33 +0200967 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
968 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200969 }
970
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100971 parsed += ret;
972 id += ret;
973
974 if ((id[0] == '[') && has_predicate) {
975 *has_predicate = 1;
976 }
977
978 return parsed;
979}
980
981/**
982 * @brief Parse schema predicate (special format internally used).
983 *
984 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200985 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100986 * key-with-value = identifier *WSP "=" *WSP
987 * ((DQUOTE string DQUOTE) /
988 * (SQUOTE string SQUOTE))
989 *
990 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200991 * @param[out] mod_name Points to the list key module name.
992 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100993 * @param[out] name Points to the list key name.
994 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100995 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100996 * @param[out] val_len Length of \p value.
997 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
998 */
Michal Vasko22448d32016-03-16 13:17:29 +0100999int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001000parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1001 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001002{
1003 const char *ptr;
1004 int parsed = 0, ret;
1005 char quote;
1006
1007 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001008 if (mod_name) {
1009 *mod_name = NULL;
1010 }
1011 if (mod_name_len) {
1012 *mod_name_len = 0;
1013 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001014 if (name) {
1015 *name = NULL;
1016 }
1017 if (nam_len) {
1018 *nam_len = 0;
1019 }
1020 if (value) {
1021 *value = NULL;
1022 }
1023 if (val_len) {
1024 *val_len = 0;
1025 }
1026 if (has_predicate) {
1027 *has_predicate = 0;
1028 }
1029
1030 if (id[0] != '[') {
1031 return -parsed;
1032 }
1033
1034 ++parsed;
1035 ++id;
1036
1037 while (isspace(id[0])) {
1038 ++parsed;
1039 ++id;
1040 }
1041
Michal Vasko22448d32016-03-16 13:17:29 +01001042 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001043 if (id[0] == '.') {
1044 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001045
1046 if (name) {
1047 *name = id;
1048 }
1049 if (nam_len) {
1050 *nam_len = ret;
1051 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001052 } else if (isdigit(id[0])) {
1053 if (id[0] == '0') {
1054 return -parsed;
1055 }
1056 ret = 1;
1057 while (isdigit(id[ret])) {
1058 ++ret;
1059 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001060
1061 if (name) {
1062 *name = id;
1063 }
1064 if (nam_len) {
1065 *nam_len = ret;
1066 }
Michal Vasko50576712017-07-28 12:28:33 +02001067 } 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 +01001068 return -parsed + ret;
1069 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001070
1071 parsed += ret;
1072 id += ret;
1073
1074 while (isspace(id[0])) {
1075 ++parsed;
1076 ++id;
1077 }
1078
1079 /* there is value as well */
1080 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001081 if (name && isdigit(**name)) {
1082 return -parsed;
1083 }
1084
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001085 ++parsed;
1086 ++id;
1087
1088 while (isspace(id[0])) {
1089 ++parsed;
1090 ++id;
1091 }
1092
1093 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1094 if ((id[0] == '\"') || (id[0] == '\'')) {
1095 quote = id[0];
1096
1097 ++parsed;
1098 ++id;
1099
1100 if ((ptr = strchr(id, quote)) == NULL) {
1101 return -parsed;
1102 }
1103 ret = ptr - id;
1104
1105 if (value) {
1106 *value = id;
1107 }
1108 if (val_len) {
1109 *val_len = ret;
1110 }
1111
1112 parsed += ret + 1;
1113 id += ret + 1;
1114 } else {
1115 return -parsed;
1116 }
1117
1118 while (isspace(id[0])) {
1119 ++parsed;
1120 ++id;
1121 }
1122 }
1123
1124 if (id[0] != ']') {
1125 return -parsed;
1126 }
1127
1128 ++parsed;
1129 ++id;
1130
1131 if ((id[0] == '[') && has_predicate) {
1132 *has_predicate = 1;
1133 }
1134
1135 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001136}
1137
1138/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001139 * @brief Resolve (find) a feature definition. Logs directly.
1140 *
1141 * @param[in] feat_name Feature name to resolve.
1142 * @param[in] len Length of \p feat_name.
1143 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001144 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1145 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001146 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001147 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001148 */
1149static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001150resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001151{
1152 char *str;
1153 const char *mod_name, *name;
1154 int mod_name_len, nam_len, i, j;
1155 const struct lys_module *module;
1156
Radek Krejci9ff0a922016-07-14 13:08:05 +02001157 assert(feature);
1158
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001159 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001160 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 +01001161 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001162 return -1;
1163 }
1164
Michal Vasko921eb6b2017-10-13 10:01:39 +02001165 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001166 if (!module) {
1167 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01001168 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001169 return -1;
1170 }
1171
Radek Krejci9ff0a922016-07-14 13:08:05 +02001172 if (module != node->module && module == lys_node_module(node)) {
1173 /* first, try to search directly in submodule where the feature was mentioned */
1174 for (j = 0; j < node->module->features_size; j++) {
1175 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1176 /* check status */
1177 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001178 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001179 return -1;
1180 }
1181 *feature = &node->module->features[j];
1182 return 0;
1183 }
1184 }
1185 }
1186
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001187 /* search in the identified module ... */
1188 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001189 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001190 /* check status */
1191 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001192 module->features[j].module, module->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->features[j];
1196 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001197 }
1198 }
1199 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001200 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001201 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001202 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1203 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001204 /* check status */
1205 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1206 module->inc[i].submodule->features[j].flags,
1207 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001208 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001209 return -1;
1210 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001211 *feature = &module->inc[i].submodule->features[j];
1212 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001213 }
1214 }
1215 }
1216
1217 /* not found */
1218 str = strndup(feat_name, len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001219 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001220 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001221 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001222}
1223
Radek Krejci9ff0a922016-07-14 13:08:05 +02001224/*
1225 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001226 * - 1 if enabled
1227 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001228 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001229static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001230resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001231{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001232 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001233
Radek Krejci9ff0a922016-07-14 13:08:05 +02001234 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001235 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001236 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001237 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001238 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001239
Radek Krejci69b8d922016-07-27 13:13:41 +02001240 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001241}
1242
1243static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001244resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001245{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001246 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001247 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001248
Radek Krejci9ff0a922016-07-14 13:08:05 +02001249 op = iff_getop(expr->expr, *index_e);
1250 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001251
Radek Krejci9ff0a922016-07-14 13:08:05 +02001252 switch (op) {
1253 case LYS_IFF_F:
1254 /* resolve feature */
1255 return resolve_feature_value(expr->features[(*index_f)++]);
1256 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001257 /* invert result */
1258 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001259 case LYS_IFF_AND:
1260 case LYS_IFF_OR:
1261 a = resolve_iffeature_recursive(expr, index_e, index_f);
1262 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001263 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001264 return a && b;
1265 } else { /* LYS_IFF_OR */
1266 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001267 }
1268 }
1269
Radek Krejciaf566332017-02-07 15:56:59 +01001270 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001271}
1272
1273int
1274resolve_iffeature(struct lys_iffeature *expr)
1275{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001276 int index_e = 0, index_f = 0;
1277
1278 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001279 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280 }
Radek Krejciaf566332017-02-07 15:56:59 +01001281 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001282}
1283
1284struct iff_stack {
1285 int size;
1286 int index; /* first empty item */
1287 uint8_t *stack;
1288};
1289
1290static int
1291iff_stack_push(struct iff_stack *stack, uint8_t value)
1292{
1293 if (stack->index == stack->size) {
1294 stack->size += 4;
1295 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001296 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001297 }
1298
1299 stack->stack[stack->index++] = value;
1300 return EXIT_SUCCESS;
1301}
1302
1303static uint8_t
1304iff_stack_pop(struct iff_stack *stack)
1305{
1306 stack->index--;
1307 return stack->stack[stack->index];
1308}
1309
1310static void
1311iff_stack_clean(struct iff_stack *stack)
1312{
1313 stack->size = 0;
1314 free(stack->stack);
1315}
1316
1317static void
1318iff_setop(uint8_t *list, uint8_t op, int pos)
1319{
1320 uint8_t *item;
1321 uint8_t mask = 3;
1322
1323 assert(pos >= 0);
1324 assert(op <= 3); /* max 2 bits */
1325
1326 item = &list[pos / 4];
1327 mask = mask << 2 * (pos % 4);
1328 *item = (*item) & ~mask;
1329 *item = (*item) | (op << 2 * (pos % 4));
1330}
1331
1332uint8_t
1333iff_getop(uint8_t *list, int pos)
1334{
1335 uint8_t *item;
1336 uint8_t mask = 3, result;
1337
1338 assert(pos >= 0);
1339
1340 item = &list[pos / 4];
1341 result = (*item) & (mask << 2 * (pos % 4));
1342 return result >> 2 * (pos % 4);
1343}
1344
1345#define LYS_IFF_LP 0x04 /* ( */
1346#define LYS_IFF_RP 0x08 /* ) */
1347
Radek Krejcicbb473e2016-09-16 14:48:32 +02001348/* internal structure for passing data for UNRES_IFFEAT */
1349struct unres_iffeat_data {
1350 struct lys_node *node;
1351 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001352 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001353};
1354
Radek Krejci9ff0a922016-07-14 13:08:05 +02001355void
1356resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1357{
1358 unsigned int e = 0, f = 0, r = 0;
1359 uint8_t op;
1360
1361 assert(iffeat);
1362
1363 if (!iffeat->expr) {
1364 goto result;
1365 }
1366
1367 do {
1368 op = iff_getop(iffeat->expr, e++);
1369 switch (op) {
1370 case LYS_IFF_NOT:
1371 if (!r) {
1372 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001373 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001374 break;
1375 case LYS_IFF_AND:
1376 case LYS_IFF_OR:
1377 if (!r) {
1378 r += 2;
1379 } else {
1380 r += 1;
1381 }
1382 break;
1383 case LYS_IFF_F:
1384 f++;
1385 if (r) {
1386 r--;
1387 }
1388 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001389 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001391
Radek Krejci9ff0a922016-07-14 13:08:05 +02001392result:
1393 if (expr_size) {
1394 *expr_size = e;
1395 }
1396 if (feat_size) {
1397 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001398 }
1399}
1400
1401int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001402resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001403 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001404{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001405 const char *c = value;
1406 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001407 int i, j, last_not, checkversion = 0;
1408 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001409 uint8_t op;
1410 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001411 struct unres_iffeat_data *iff_data;
Michal Vasko53b7da02018-02-13 15:28:42 +01001412 struct ly_ctx *ctx = node->module->ctx;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001413
Radek Krejci9ff0a922016-07-14 13:08:05 +02001414 assert(c);
1415
1416 if (isspace(c[0])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001417 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001418 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001419 }
1420
Radek Krejci9ff0a922016-07-14 13:08:05 +02001421 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1422 for (i = j = last_not = 0; c[i]; i++) {
1423 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001424 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001425 j++;
1426 continue;
1427 } else if (c[i] == ')') {
1428 j--;
1429 continue;
1430 } else if (isspace(c[i])) {
1431 continue;
1432 }
1433
1434 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1435 if (c[i + r] == '\0') {
Michal Vasko53b7da02018-02-13 15:28:42 +01001436 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001437 return EXIT_FAILURE;
1438 } else if (!isspace(c[i + r])) {
1439 /* feature name starting with the not/and/or */
1440 last_not = 0;
1441 f_size++;
1442 } else if (c[i] == 'n') { /* not operation */
1443 if (last_not) {
1444 /* double not */
1445 expr_size = expr_size - 2;
1446 last_not = 0;
1447 } else {
1448 last_not = 1;
1449 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001450 } else { /* and, or */
1451 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001452 /* not a not operation */
1453 last_not = 0;
1454 }
1455 i += r;
1456 } else {
1457 f_size++;
1458 last_not = 0;
1459 }
1460 expr_size++;
1461
1462 while (!isspace(c[i])) {
1463 if (!c[i] || c[i] == ')') {
1464 i--;
1465 break;
1466 }
1467 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001468 }
1469 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001470 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001471 /* not matching count of ( and ) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001472 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001473 return EXIT_FAILURE;
1474 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001475
Radek Krejci69b8d922016-07-27 13:13:41 +02001476 if (checkversion || expr_size > 1) {
1477 /* check that we have 1.1 module */
Radek Krejci13fde922018-05-16 10:45:58 +02001478 if (node->module->version != LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001479 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1480 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 +02001481 return EXIT_FAILURE;
1482 }
1483 }
1484
Radek Krejci9ff0a922016-07-14 13:08:05 +02001485 /* allocate the memory */
1486 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001487 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488 stack.stack = malloc(expr_size * sizeof *stack.stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001489 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001490 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001491 f_size--; expr_size--; /* used as indexes from now */
1492
1493 for (i--; i >= 0; i--) {
1494 if (c[i] == ')') {
1495 /* push it on stack */
1496 iff_stack_push(&stack, LYS_IFF_RP);
1497 continue;
1498 } else if (c[i] == '(') {
1499 /* pop from the stack into result all operators until ) */
1500 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1501 iff_setop(iffeat_expr->expr, op, expr_size--);
1502 }
1503 continue;
1504 } else if (isspace(c[i])) {
1505 continue;
1506 }
1507
1508 /* end operator or operand -> find beginning and get what is it */
1509 j = i + 1;
1510 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1511 i--;
1512 }
1513 i++; /* get back by one step */
1514
1515 if (!strncmp(&c[i], "not ", 4)) {
1516 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1517 /* double not */
1518 iff_stack_pop(&stack);
1519 } else {
1520 /* not has the highest priority, so do not pop from the stack
1521 * as in case of AND and OR */
1522 iff_stack_push(&stack, LYS_IFF_NOT);
1523 }
1524 } else if (!strncmp(&c[i], "and ", 4)) {
1525 /* as for OR - pop from the stack all operators with the same or higher
1526 * priority and store them to the result, then push the AND to the stack */
1527 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1528 op = iff_stack_pop(&stack);
1529 iff_setop(iffeat_expr->expr, op, expr_size--);
1530 }
1531 iff_stack_push(&stack, LYS_IFF_AND);
1532 } else if (!strncmp(&c[i], "or ", 3)) {
1533 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1534 op = iff_stack_pop(&stack);
1535 iff_setop(iffeat_expr->expr, op, expr_size--);
1536 }
1537 iff_stack_push(&stack, LYS_IFF_OR);
1538 } else {
1539 /* feature name, length is j - i */
1540
1541 /* add it to the result */
1542 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1543
1544 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001545 * forward referenced, we have to keep the feature name in auxiliary
1546 * structure passed into unres */
1547 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01001548 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001549 iff_data->node = node;
1550 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001551 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001552 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1553 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001554 f_size--;
1555
1556 if (r == -1) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01001557 lydict_remove(node->module->ctx, iff_data->fname);
Pavol Vican4d084512016-09-29 16:38:12 +02001558 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001559 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001560 }
1561 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001562 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001563 while (stack.index) {
1564 op = iff_stack_pop(&stack);
1565 iff_setop(iffeat_expr->expr, op, expr_size--);
1566 }
1567
1568 if (++expr_size || ++f_size) {
1569 /* not all expected operators and operands found */
Michal Vasko53b7da02018-02-13 15:28:42 +01001570 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001571 rc = EXIT_FAILURE;
1572 } else {
1573 rc = EXIT_SUCCESS;
1574 }
1575
1576error:
1577 /* cleanup */
1578 iff_stack_clean(&stack);
1579
1580 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001581}
1582
1583/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001584 * @brief Resolve (find) a data node based on a schema-nodeid.
1585 *
1586 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1587 * module).
1588 *
1589 */
1590struct lyd_node *
1591resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1592{
1593 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001594 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001595 const struct lys_node *schema = NULL;
1596
1597 assert(nodeid && start);
1598
1599 if (nodeid[0] == '/') {
1600 return NULL;
1601 }
1602
1603 str = p = strdup(nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01001604 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001605
Michal Vasko3edeaf72016-02-11 13:17:43 +01001606 while (p) {
1607 token = p;
1608 p = strchr(p, '/');
1609 if (p) {
1610 *p = '\0';
1611 p++;
1612 }
1613
Radek Krejci5da4eb62016-04-08 14:45:51 +02001614 if (p) {
1615 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001616 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001617 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001618 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001619 result = NULL;
1620 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001621 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001622
Radek Krejci5da4eb62016-04-08 14:45:51 +02001623 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1624 continue;
1625 }
1626 } else {
1627 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001628 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001629 || !schema) {
1630 result = NULL;
1631 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001632 }
1633 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001634 LY_TREE_FOR(result ? result->child : start, iter) {
1635 if (iter->schema == schema) {
1636 /* move in data tree according to returned schema */
1637 result = iter;
1638 break;
1639 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001640 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001641 if (!iter) {
1642 /* instance not found */
1643 result = NULL;
1644 break;
1645 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001646 }
1647 free(str);
1648
1649 return result;
1650}
1651
Radek Krejci1a9c3612017-04-24 14:49:43 +02001652int
Michal Vasko50576712017-07-28 12:28:33 +02001653schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1654 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001655{
1656 const struct lys_module *prefix_mod;
1657
Michal Vaskocdb3f062018-02-01 09:55:06 +01001658 /* handle special names */
1659 if (name[0] == '*') {
1660 return 2;
1661 } else if (name[0] == '.') {
1662 return 3;
1663 }
1664
Michal Vasko50576712017-07-28 12:28:33 +02001665 /* name check */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001666 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02001667 return 1;
1668 }
1669
Radek Krejcibdf92362016-04-08 14:43:34 +02001670 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001671 if (mod_name) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001672 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vasko50576712017-07-28 12:28:33 +02001673 if (!prefix_mod) {
1674 return -1;
1675 }
1676 } else {
1677 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001678 }
1679 if (prefix_mod != lys_node_module(sibling)) {
1680 return 1;
1681 }
1682
Michal Vasko50576712017-07-28 12:28:33 +02001683 /* match */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001684 return 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001685}
1686
Michal Vasko50576712017-07-28 12:28:33 +02001687/* keys do not have to be ordered and do not have to be all of them */
1688static int
1689resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1690 const struct lys_module *cur_module, int *nodeid_end)
1691{
1692 int mod_len, nam_len, has_predicate, r, i;
1693 const char *model, *name;
1694 struct lys_node_list *list;
1695
1696 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1697 return 1;
1698 }
1699
1700 list = (struct lys_node_list *)node;
1701 do {
1702 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1703 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001704 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001705 return -1;
1706 }
1707 nodeid += r;
1708
1709 if (node->nodetype == LYS_LEAFLIST) {
1710 /* just check syntax */
1711 if (model || !name || (name[0] != '.') || has_predicate) {
1712 return 1;
1713 }
1714 break;
1715 } else {
1716 /* check the key */
1717 for (i = 0; i < list->keys_size; ++i) {
1718 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1719 continue;
1720 }
1721 if (model) {
1722 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1723 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1724 continue;
1725 }
1726 } else {
1727 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1728 continue;
1729 }
1730 }
1731
1732 /* match */
1733 break;
1734 }
1735
1736 if (i == list->keys_size) {
1737 return 1;
1738 }
1739 }
1740 } while (has_predicate);
1741
1742 if (!nodeid[0]) {
1743 *nodeid_end = 1;
1744 }
1745 return 0;
1746}
1747
Michal Vasko97234262018-02-01 09:53:01 +01001748/* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001749 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001750int
Michal Vasko97234262018-02-01 09:53:01 +01001751resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
Michal Vasko50576712017-07-28 12:28:33 +02001752 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001753{
PavolVicanb28bbff2018-02-21 00:44:02 +01001754 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vasko97234262018-02-01 09:53:01 +01001755 const struct lys_node *sibling, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001756 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001757 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
PavolVicanb28bbff2018-02-21 00:44:02 +01001758 int yang_data_name_len, backup_mod_name_len = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001759 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidaa547a2017-09-22 15:56:27 +02001760 const struct lys_module *start_mod, *aux_mod = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02001761 char *str;
Michal Vasko53b7da02018-02-13 15:28:42 +01001762 struct ly_ctx *ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763
Michal Vasko97234262018-02-01 09:53:01 +01001764 assert(nodeid && (start_parent || cur_module) && ret);
Michal Vasko50576712017-07-28 12:28:33 +02001765 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001766
Michal Vasko50576712017-07-28 12:28:33 +02001767 if (!cur_module) {
Michal Vasko97234262018-02-01 09:53:01 +01001768 cur_module = lys_node_module(start_parent);
Michal Vasko50576712017-07-28 12:28:33 +02001769 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001770 ctx = cur_module->ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771 id = nodeid;
1772
PavolVican195cf392018-02-23 13:24:45 +01001773 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
PavolVicanb28bbff2018-02-21 00:44:02 +01001774 if (r < 1) {
1775 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1776 return -1;
1777 }
1778
1779 if (name[0] == '#') {
1780 if (is_relative) {
1781 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1782 return -1;
1783 }
1784 yang_data_name = name + 1;
1785 yang_data_name_len = nam_len - 1;
1786 backup_mod_name = mod_name;
1787 backup_mod_name_len = mod_name_len;
1788 id += r;
1789 } else {
1790 is_relative = -1;
1791 }
1792
Michal Vasko50576712017-07-28 12:28:33 +02001793 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1794 (extended ? &all_desc : NULL), extended);
1795 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001796 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001797 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001798 }
1799 id += r;
1800
PavolVicanb28bbff2018-02-21 00:44:02 +01001801 if (backup_mod_name) {
1802 mod_name = backup_mod_name;
1803 mod_name_len = backup_mod_name_len;
1804 }
1805
Michal Vasko97234262018-02-01 09:53:01 +01001806 if (is_relative && !start_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001807 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
Michal Vasko3edeaf72016-02-11 13:17:43 +01001808 return -1;
1809 }
1810
1811 /* descendant-schema-nodeid */
1812 if (is_relative) {
Michal Vasko97234262018-02-01 09:53:01 +01001813 cur_module = start_mod = lys_node_module(start_parent);
Michal Vasko24476fa2017-03-08 12:33:48 +01001814
Michal Vasko3edeaf72016-02-11 13:17:43 +01001815 /* absolute-schema-nodeid */
1816 } else {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001817 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01001818 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001819 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001820 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001821 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001822 return -1;
1823 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001824 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01001825 if (yang_data_name) {
1826 start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1827 if (!start_parent) {
1828 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1829 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1830 free(str);
1831 return -1;
1832 }
1833 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001834 }
1835
1836 while (1) {
1837 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001838 last_aug = NULL;
1839
1840 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001841 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1842 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001843 /* we are getting into another module (augment) */
Michal Vasko921eb6b2017-10-13 10:01:39 +02001844 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskobb520442017-05-23 10:55:18 +02001845 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001846 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001847 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001848 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001849 return -1;
1850 }
1851 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001852 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001853 * because this module may be not implemented and it augments something in another module and
1854 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001855 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001856 }
1857
1858 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001859 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001860get_next_augment:
1861 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1862 }
1863 }
1864
1865 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vaskocb45f472018-02-12 10:47:42 +01001866 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02001867 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1868
1869 /* resolve predicate */
1870 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1871 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1872 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001873 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001874 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001875 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001876 }
Michal Vasko50576712017-07-28 12:28:33 +02001877 } else if (!id[0]) {
1878 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001879 }
Michal Vasko50576712017-07-28 12:28:33 +02001880
1881 if (r == 0) {
1882 /* one matching result */
1883 if (nodeid_end) {
1884 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001885 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001886 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1887 } else {
1888 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1889 return -1;
1890 }
1891 start_parent = sibling;
1892 }
1893 break;
1894 } else if (r == 1) {
1895 continue;
1896 } else if (r == 2) {
1897 /* "*" */
1898 if (!*ret) {
1899 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001900 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001901 }
1902 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1903 if (all_desc) {
1904 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1905 if (elem != sibling) {
1906 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1907 }
1908
1909 LY_TREE_DFS_END(sibling, next, elem);
1910 }
1911 }
1912 } else if (r == 3) {
1913 /* "." */
1914 if (!*ret) {
1915 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001916 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001917 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1918 }
1919 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1920 if (all_desc) {
1921 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1922 if (elem != sibling) {
1923 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1924 }
1925
1926 LY_TREE_DFS_END(sibling, next, elem);
1927 }
1928 }
1929 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001930 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001931 return -1;
1932 }
1933 }
1934
1935 /* skip predicate */
1936 if (extended && has_predicate) {
1937 while (id[0] == '[') {
1938 id = strchr(id, ']');
1939 if (!id) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001940 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001941 return -1;
1942 }
1943 ++id;
1944 }
1945 }
1946
1947 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1948 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001949 }
1950
1951 /* no match */
1952 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001953 if (last_aug) {
1954 /* it still could be in another augment */
1955 goto get_next_augment;
1956 }
Michal Vasko50576712017-07-28 12:28:33 +02001957 if (no_node_error) {
1958 str = strndup(nodeid, (name - nodeid) + nam_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001959 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001960 free(str);
1961 return -1;
1962 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001963 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001964 return EXIT_SUCCESS;
1965 }
1966
Michal Vasko50576712017-07-28 12:28:33 +02001967 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1968 (extended ? &all_desc : NULL), extended);
1969 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001970 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001971 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001972 }
1973 id += r;
1974 }
1975
1976 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01001977 LOGINT(ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001978 return -1;
1979}
1980
Radek Krejcif3c71de2016-04-11 12:45:46 +02001981/* unique, refine,
1982 * >0 - unexpected char on position (ret - 1),
1983 * 0 - ok (but ret can still be NULL),
1984 * -1 - error,
1985 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001986int
1987resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001988 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001989{
1990 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001991 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001992 int r, nam_len, mod_name_len, is_relative = -1;
1993 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001994 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001995
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001996 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001997 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001998
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001999 if (!start) {
2000 /* leaf not found */
2001 return 0;
2002 }
2003
Michal Vasko3edeaf72016-02-11 13:17:43 +01002004 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02002005 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002006
Michal Vasko50576712017-07-28 12:28:33 +02002007 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 +01002008 return ((id - nodeid) - r) + 1;
2009 }
2010 id += r;
2011
2012 if (!is_relative) {
2013 return -1;
2014 }
2015
Michal Vasko24476fa2017-03-08 12:33:48 +01002016 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02002017 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01002018 start_parent = lys_parent(start_parent);
2019 }
2020
Michal Vasko3edeaf72016-02-11 13:17:43 +01002021 while (1) {
2022 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002023 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vaskocb45f472018-02-12 10:47:42 +01002024 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002025 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2026 if (r == 0) {
2027 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002028 if (!(sibling->nodetype & ret_nodetype)) {
2029 /* wrong node type, too bad */
2030 continue;
2031 }
2032 *ret = sibling;
2033 return EXIT_SUCCESS;
2034 }
Michal Vasko50576712017-07-28 12:28:33 +02002035 start_parent = sibling;
2036 break;
2037 } else if (r == 1) {
2038 continue;
2039 } else {
2040 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002041 }
2042 }
2043
2044 /* no match */
2045 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002046 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002047 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02002048 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2049 *ret = NULL;
2050 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002051 }
2052
Michal Vasko50576712017-07-28 12:28:33 +02002053 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 +01002054 return ((id - nodeid) - r) + 1;
2055 }
2056 id += r;
2057 }
2058
2059 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002060 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002061 return -1;
2062}
2063
2064/* choice default */
2065int
2066resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2067{
2068 /* cannot actually be a path */
2069 if (strchr(nodeid, '/')) {
2070 return -1;
2071 }
2072
Michal Vaskodc300b02017-04-07 14:09:20 +02002073 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002074}
2075
2076/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2077static int
2078resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2079{
2080 const struct lys_module *module;
2081 const char *mod_prefix, *name;
2082 int i, mod_prefix_len, nam_len;
2083
2084 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002085 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 +01002086 return -i + 1;
2087 }
2088
Michal Vasko921eb6b2017-10-13 10:01:39 +02002089 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002090 if (!module) {
2091 return -1;
2092 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002093 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002094 start = module->data;
2095 }
2096
2097 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2098
2099 return EXIT_SUCCESS;
2100}
2101
2102int
2103resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2104 const struct lys_node **ret)
2105{
2106 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002107 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002108 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002109 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002110
2111 assert(nodeid && module && ret);
2112 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2113
2114 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002115 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002116
Michal Vasko50576712017-07-28 12:28:33 +02002117 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 +01002118 return ((id - nodeid) - r) + 1;
2119 }
2120 id += r;
2121
2122 if (is_relative) {
2123 return -1;
2124 }
2125
Michal Vasko921eb6b2017-10-13 10:01:39 +02002126 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01002127 if (!abs_start_mod) {
2128 return -1;
2129 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002130
2131 while (1) {
2132 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002133 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vaskocb45f472018-02-12 10:47:42 +01002134 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002135 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2136 if (r == 0) {
2137 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002138 if (!(sibling->nodetype & ret_nodetype)) {
2139 /* wrong node type, too bad */
2140 continue;
2141 }
2142 *ret = sibling;
2143 return EXIT_SUCCESS;
2144 }
Michal Vasko50576712017-07-28 12:28:33 +02002145 start_parent = sibling;
2146 break;
2147 } else if (r == 1) {
2148 continue;
2149 } else {
2150 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002151 }
2152 }
2153
2154 /* no match */
2155 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002156 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002157 return EXIT_SUCCESS;
2158 }
2159
Michal Vasko50576712017-07-28 12:28:33 +02002160 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 +01002161 return ((id - nodeid) - r) + 1;
2162 }
2163 id += r;
2164 }
2165
2166 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002167 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002168 return -1;
2169}
2170
Michal Vaskoe733d682016-03-14 09:08:27 +01002171static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002172resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002173{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002174 const char *mod_name, *name;
2175 int mod_name_len, nam_len, has_predicate, i;
2176 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002177
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002178 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 +02002179 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002180 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002181 return -1;
2182 }
2183
2184 predicate += i;
2185 *parsed += i;
2186
Michal Vasko58c2aab2017-01-05 10:02:05 +01002187 if (!isdigit(name[0])) {
2188 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002189 key = (struct lys_node *)list->keys[i];
2190 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002191 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002192 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002193 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002194
Michal Vasko58c2aab2017-01-05 10:02:05 +01002195 if (i == list->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002196 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko58c2aab2017-01-05 10:02:05 +01002197 return -1;
2198 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002199 }
2200
2201 /* more predicates? */
2202 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002203 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002204 }
2205
2206 return 0;
2207}
2208
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002209/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002210const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002211resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002212{
Michal Vasko53b7da02018-02-13 15:28:42 +01002213 char *str;
PavolVicanb28bbff2018-02-21 00:44:02 +01002214 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vaskob3744402017-08-03 14:23:58 +02002215 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002216 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
PavolVicanb28bbff2018-02-21 00:44:02 +01002217 int yang_data_name_len, backup_mod_name_len;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002218 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002219 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002220
Michal Vasko3547c532016-03-14 09:40:50 +01002221 assert(nodeid && (ctx || start));
2222 if (!ctx) {
2223 ctx = start->module->ctx;
2224 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002225
2226 id = nodeid;
2227
PavolVican195cf392018-02-23 13:24:45 +01002228 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
PavolVicanb28bbff2018-02-21 00:44:02 +01002229 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2230 return NULL;
2231 }
2232
2233 if (name[0] == '#') {
2234 if (is_relative) {
2235 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2236 return NULL;
2237 }
2238 yang_data_name = name + 1;
2239 yang_data_name_len = nam_len - 1;
2240 backup_mod_name = mod_name;
2241 backup_mod_name_len = mod_name_len;
2242 id += r;
2243 } else {
2244 is_relative = -1;
2245 }
2246
Michal Vasko50576712017-07-28 12:28:33 +02002247 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 +01002248 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002249 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002250 }
2251 id += r;
2252
PavolVicanb28bbff2018-02-21 00:44:02 +01002253 if (backup_mod_name) {
2254 mod_name = backup_mod_name;
2255 mod_name_len = backup_mod_name_len;
2256 }
2257
Michal Vasko3edeaf72016-02-11 13:17:43 +01002258 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002259 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002260 start_parent = start;
2261 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2262 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002263 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002264 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002265 } else {
2266 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002267 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002268 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
Michal Vasko10728b52016-04-07 14:26:29 +02002269 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002270 return NULL;
2271 }
2272
Michal Vasko53b7da02018-02-13 15:28:42 +01002273 str = strndup(mod_name, mod_name_len);
2274 module = ly_ctx_get_module(ctx, str, NULL, 1);
2275 free(str);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002276
Michal Vaskof68a49e2017-08-14 13:23:37 +02002277 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002278 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002279 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002280 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002281 return NULL;
2282 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002283 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01002284 if (yang_data_name) {
2285 start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2286 if (!start_parent) {
2287 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2288 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2289 free(str);
2290 return NULL;
2291 }
2292 }
Michal Vasko3547c532016-03-14 09:40:50 +01002293
2294 /* now it's as if there was no module name */
2295 mod_name = NULL;
2296 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002297 }
2298
Michal Vaskof68a49e2017-08-14 13:23:37 +02002299 prev_mod = module;
2300
Michal Vasko3edeaf72016-02-11 13:17:43 +01002301 while (1) {
2302 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002303 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002304 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002305 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002306 /* output check */
2307 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2308 if (parent) {
2309 if (output && (parent->nodetype == LYS_INPUT)) {
2310 continue;
2311 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2312 continue;
2313 }
2314 }
2315
Michal Vasko3edeaf72016-02-11 13:17:43 +01002316 /* module check */
2317 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002318 /* will also find an augment module */
Michal Vasko53b7da02018-02-13 15:28:42 +01002319 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002320
Michal Vasko3edeaf72016-02-11 13:17:43 +01002321 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002322 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002323 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002324 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002325 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002326 }
2327 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002328 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002329 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002330 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002331 continue;
2332 }
2333
Michal Vaskoe733d682016-03-14 09:08:27 +01002334 /* do we have some predicates on it? */
2335 if (has_predicate) {
2336 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002337 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002338 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002339 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002340 return NULL;
2341 }
2342 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002343 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002344 return NULL;
2345 }
2346 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002347 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002348 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002349 }
2350 id += r;
2351 }
2352
Michal Vasko3edeaf72016-02-11 13:17:43 +01002353 /* the result node? */
2354 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002355 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002356 }
2357
Michal Vaskodc300b02017-04-07 14:09:20 +02002358 /* move down the tree, if possible */
2359 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002360 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskodc300b02017-04-07 14:09:20 +02002361 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002362 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002363 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002364
2365 /* update prev mod */
2366 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002367 break;
2368 }
2369 }
2370
2371 /* no match */
2372 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002373 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002374 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002375 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002376 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002377 }
2378
Michal Vasko50576712017-07-28 12:28:33 +02002379 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 +01002380 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002381 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002382 }
2383 id += r;
2384 }
2385
2386 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002387 LOGINT(ctx);
Michal Vaskoe733d682016-03-14 09:08:27 +01002388 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002389}
2390
Michal Vaskofebd13d2018-05-17 10:42:24 +02002391/* internal parsed predicate structure */
2392struct parsed_pred {
2393 const char *mod_name;
2394 int mod_name_len;
2395 const char *name;
2396 int nam_len;
2397 const char *value;
2398 int val_len;
2399};
2400
Michal Vasko22448d32016-03-16 13:17:29 +01002401static int
Michal Vaskofebd13d2018-05-17 10:42:24 +02002402resolve_partial_json_data_list_predicate(struct parsed_pred *pp, int pp_len, struct lyd_node *node, int position)
Michal Vasko22448d32016-03-16 13:17:29 +01002403{
Michal Vaskofebd13d2018-05-17 10:42:24 +02002404 const char *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002405 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002406 struct lyd_node_leaf_list *key;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002407 struct lys_node_list *slist;
Michal Vasko53b7da02018-02-13 15:28:42 +01002408 struct ly_ctx *ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002409
Radek Krejci61a86c62016-03-24 11:06:44 +01002410 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002411 assert(node->schema->nodetype == LYS_LIST);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002412 assert(pp && pp_len);
2413
Michal Vasko53b7da02018-02-13 15:28:42 +01002414 ctx = node->schema->module->ctx;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002415 slist = (struct lys_node_list *)node->schema;
Michal Vasko22448d32016-03-16 13:17:29 +01002416
Michal Vasko53adfc72017-01-06 10:39:10 +01002417 /* is the predicate a number? */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002418 if (isdigit(pp[0].name[0])) {
2419 if (position == atoi(pp[0].name)) {
Michal Vasko53adfc72017-01-06 10:39:10 +01002420 /* match */
Michal Vasko53adfc72017-01-06 10:39:10 +01002421 return 0;
2422 } else {
2423 /* not a match */
2424 return 1;
2425 }
2426 }
2427
Michal Vaskofebd13d2018-05-17 10:42:24 +02002428 /* basic checks */
2429 if (pp_len > slist->keys_size) {
2430 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2431 return -1;
2432 } else if (pp_len < slist->keys_size) {
2433 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp_len]->name);
2434 return -1;
Michal Vasko53adfc72017-01-06 10:39:10 +01002435 }
2436
Michal Vaskof29903d2016-04-18 13:13:10 +02002437 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002438 if (!key) {
2439 /* it is not a position, so we need a key for it to be a match */
2440 return 1;
2441 }
2442
2443 /* go through all the keys */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002444 for (i = 0; i < slist->keys_size; ++i) {
2445 if (strncmp(key->schema->name, pp[i].name, pp[i].nam_len) || key->schema->name[pp[i].nam_len]) {
2446 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp[i].name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002447 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002448 }
2449
Michal Vaskofebd13d2018-05-17 10:42:24 +02002450 if (pp[i].mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002451 /* specific module, check that the found key is from that module */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002452 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp[i].mod_name, pp[i].mod_name_len)
2453 || lyd_node_module((struct lyd_node *)key)->name[pp[i].mod_name_len]) {
2454 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002455 return -1;
2456 }
Michal Vasko50576712017-07-28 12:28:33 +02002457
2458 /* but if the module is the same as the parent, it should have been omitted */
2459 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002460 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp[i].name);
Michal Vasko50576712017-07-28 12:28:33 +02002461 return -1;
2462 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002463 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002464 /* no module, so it must be the same as the list (parent) */
2465 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002466 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002467 return -1;
2468 }
2469 }
2470
Michal Vasko9ba34de2016-12-07 12:21:19 +01002471 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002472 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002473 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2474 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002475 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2476 } else {
2477 key_val = key->value_str;
2478 }
2479
Michal Vasko22448d32016-03-16 13:17:29 +01002480 /* value does not match */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002481 if (strncmp(key_val, pp[i].value, pp[i].val_len) || key_val[pp[i].val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002482 return 1;
2483 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002484
2485 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002486 }
2487
Michal Vasko22448d32016-03-16 13:17:29 +01002488 return 0;
2489}
2490
Radek Krejci45826012016-08-24 15:07:57 +02002491/**
2492 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2493 *
2494 * @param[in] nodeid Node data path to find
2495 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2496 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2497 * @param[out] parsed Number of characters processed in \p id
2498 * @return The closes parent (or the node itself) from the path
2499 */
Michal Vasko22448d32016-03-16 13:17:29 +01002500struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002501resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2502 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002503{
Michal Vasko53b7da02018-02-13 15:28:42 +01002504 char *str;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002505 const char *id, *mod_name, *name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002506 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002507 int has_predicate, last_parsed = 0, llval_len;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002508 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002509 struct lyd_node_leaf_list *llist;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002510 const struct lys_module *prefix_mod, *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002511 struct ly_ctx *ctx;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002512 struct parsed_pred *pp = NULL;
2513 int pp_len;
Michal Vasko22448d32016-03-16 13:17:29 +01002514
2515 assert(nodeid && start && parsed);
2516
2517 ctx = start->schema->module->ctx;
2518 id = nodeid;
2519
PavolVican195cf392018-02-23 13:24:45 +01002520 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1)) < 1) {
PavolVicanb28bbff2018-02-21 00:44:02 +01002521 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002522 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002523 }
2524
2525 if (name[0] == '#') {
2526 if (is_relative) {
2527 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002528 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002529 }
PavolVicanb28bbff2018-02-21 00:44:02 +01002530 id += r;
2531 last_parsed = r;
2532 } else {
2533 is_relative = -1;
2534 }
2535
Michal Vaskofebd13d2018-05-17 10:42:24 +02002536 /* parse forst nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002537 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 +01002538 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002539 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002540 }
2541 id += r;
2542 /* add it to parsed only after the data node was actually found */
PavolVicanb28bbff2018-02-21 00:44:02 +01002543 last_parsed += r;
Michal Vasko22448d32016-03-16 13:17:29 +01002544
2545 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002546 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002547 start = start->child;
2548 } else {
2549 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002550 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002551 }
2552
Michal Vaskofebd13d2018-05-17 10:42:24 +02002553 /* do not duplicate code, use predicate parsing from the loop */
2554 goto parse_predicates;
2555
Michal Vasko22448d32016-03-16 13:17:29 +01002556 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002557 list_instance_position = 0;
2558
Michal Vasko22448d32016-03-16 13:17:29 +01002559 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002560 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002561 if (lys_parent(sibling->schema)) {
2562 if (options & LYD_PATH_OPT_OUTPUT) {
2563 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002564 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002565 goto error;
Michal Vasko2411b942016-03-23 13:50:03 +01002566 }
2567 } else {
2568 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002569 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002570 goto error;
Michal Vasko2411b942016-03-23 13:50:03 +01002571 }
2572 }
2573 }
2574
Michal Vasko22448d32016-03-16 13:17:29 +01002575 /* name match */
2576 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2577
2578 /* module check */
2579 if (mod_name) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002580 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002581
Michal Vasko22448d32016-03-16 13:17:29 +01002582 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002583 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002584 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002585 free(str);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002586 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002587 }
2588 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002589 prefix_mod = prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002590 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002591 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002592 continue;
2593 }
2594
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002595 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002596 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko24affa02018-04-03 09:06:06 +02002597 if (sibling->schema->flags & LYS_CONFIG_R) {
2598 /* state leaf-lists will never match */
2599 continue;
2600 }
2601
Michal Vasko9ba34de2016-12-07 12:21:19 +01002602 llist = (struct lyd_node_leaf_list *)sibling;
2603
Michal Vaskofebd13d2018-05-17 10:42:24 +02002604 if (pp) {
2605 if (pp_len > 1) {
2606 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2607 goto error;
Michal Vaskof0a50972016-10-19 11:33:55 +02002608 }
Michal Vaskofebd13d2018-05-17 10:42:24 +02002609 if ((pp[0].name[0] != '.') || (pp[0].nam_len != 1)) {
2610 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp[0].name[0], pp[0].name);
2611 goto error;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002612 }
Michal Vaskofebd13d2018-05-17 10:42:24 +02002613 llist_value = pp[0].value;
2614 llval_len = pp[0].val_len;
2615
Michal Vaskof0a50972016-10-19 11:33:55 +02002616 } else {
Michal Vaskof0a50972016-10-19 11:33:55 +02002617 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002618 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002619 }
2620 }
2621
Michal Vasko21b90ce2017-09-19 09:38:27 +02002622 /* make value canonical (remove module name prefix) unless it was specified with it */
Michal Vaskod6d51292017-09-22 14:30:48 +02002623 if (llist_value && !strchr(llist_value, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002624 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2625 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002626 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2627 } else {
2628 data_val = llist->value_str;
2629 }
2630
2631 if ((!llist_value && data_val && data_val[0])
2632 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002633 continue;
2634 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002635
Radek Krejci45826012016-08-24 15:07:57 +02002636 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002637 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002638 if (!pp) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002639 /* none match */
2640 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002641 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002642
2643 ++list_instance_position;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002644 ret = resolve_partial_json_data_list_predicate(pp, pp_len, sibling, list_instance_position);
Michal Vasko22448d32016-03-16 13:17:29 +01002645 if (ret == -1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002646 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002647 } else if (ret == 1) {
2648 /* this list instance does not match */
2649 continue;
2650 }
Michal Vasko22448d32016-03-16 13:17:29 +01002651 }
2652
Michal Vaskofebd13d2018-05-17 10:42:24 +02002653 /* we found a next matching node */
Michal Vasko22448d32016-03-16 13:17:29 +01002654 *parsed += last_parsed;
2655
2656 /* the result node? */
2657 if (!id[0]) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002658 free(pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002659 return sibling;
2660 }
2661
2662 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002663 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002664 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002665 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002666 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002667 last_match = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002668 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002669 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002670 break;
2671 }
2672 }
2673
2674 /* no match, return last match */
2675 if (!sibling) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002676 free(pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002677 return last_match;
2678 }
2679
Michal Vaskofebd13d2018-05-17 10:42:24 +02002680 /* parse nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002681 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 +01002682 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002683 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002684 }
2685 id += r;
2686 last_parsed = r;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002687
2688parse_predicates:
2689 /* parse all the predicates */
2690 free(pp);
2691 pp = NULL;
2692 pp_len = 0;
2693 while (has_predicate) {
2694 ++pp_len;
2695 pp = ly_realloc(pp, pp_len * sizeof *pp);
2696 if ((r = parse_schema_json_predicate(id, &pp[pp_len - 1].mod_name, &pp[pp_len - 1].mod_name_len,
2697 &pp[pp_len - 1].name, &pp[pp_len - 1].nam_len, &pp[pp_len - 1].value,
2698 &pp[pp_len - 1].val_len, &has_predicate)) < 1) {
2699 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2700 goto error;
2701 }
2702
2703 id += r;
2704 last_parsed += r;
2705 }
Michal Vasko22448d32016-03-16 13:17:29 +01002706 }
2707
Michal Vaskofebd13d2018-05-17 10:42:24 +02002708error:
Michal Vasko238bd2f2016-03-23 09:39:01 +01002709 *parsed = -1;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002710 free(pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002711 return NULL;
2712}
2713
Michal Vasko3edeaf72016-02-11 13:17:43 +01002714/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002715 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002716 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002717 *
Michal Vasko53b7da02018-02-13 15:28:42 +01002718 * @param[in] ctx Context for errors.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002719 * @param[in] str_restr Restriction as a string.
2720 * @param[in] type Type of the restriction.
2721 * @param[out] ret Final interval structure that starts with
2722 * the interval of the initial type, continues with intervals
2723 * of any superior types derived from the initial one, and
2724 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002725 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002726 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002727 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002728int
Michal Vasko53b7da02018-02-13 15:28:42 +01002729resolve_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 +02002730{
2731 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002732 int kind;
Michal Vaskof75b2772018-03-14 09:55:33 +01002733 int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2734 uint64_t local_umin, local_umax = 0;
2735 uint8_t local_fdig = 0;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002736 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002737 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002738
2739 switch (type->base) {
2740 case LY_TYPE_BINARY:
2741 kind = 0;
2742 local_umin = 0;
2743 local_umax = 18446744073709551615UL;
2744
2745 if (!str_restr && type->info.binary.length) {
2746 str_restr = type->info.binary.length->expr;
2747 }
2748 break;
2749 case LY_TYPE_DEC64:
2750 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002751 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2752 local_fmax = __INT64_C(9223372036854775807);
2753 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002754
2755 if (!str_restr && type->info.dec64.range) {
2756 str_restr = type->info.dec64.range->expr;
2757 }
2758 break;
2759 case LY_TYPE_INT8:
2760 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002761 local_smin = __INT64_C(-128);
2762 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002763
2764 if (!str_restr && type->info.num.range) {
2765 str_restr = type->info.num.range->expr;
2766 }
2767 break;
2768 case LY_TYPE_INT16:
2769 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002770 local_smin = __INT64_C(-32768);
2771 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002772
2773 if (!str_restr && type->info.num.range) {
2774 str_restr = type->info.num.range->expr;
2775 }
2776 break;
2777 case LY_TYPE_INT32:
2778 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002779 local_smin = __INT64_C(-2147483648);
2780 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002781
2782 if (!str_restr && type->info.num.range) {
2783 str_restr = type->info.num.range->expr;
2784 }
2785 break;
2786 case LY_TYPE_INT64:
2787 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002788 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2789 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002790
2791 if (!str_restr && type->info.num.range) {
2792 str_restr = type->info.num.range->expr;
2793 }
2794 break;
2795 case LY_TYPE_UINT8:
2796 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002797 local_umin = __UINT64_C(0);
2798 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002799
2800 if (!str_restr && type->info.num.range) {
2801 str_restr = type->info.num.range->expr;
2802 }
2803 break;
2804 case LY_TYPE_UINT16:
2805 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002806 local_umin = __UINT64_C(0);
2807 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002808
2809 if (!str_restr && type->info.num.range) {
2810 str_restr = type->info.num.range->expr;
2811 }
2812 break;
2813 case LY_TYPE_UINT32:
2814 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002815 local_umin = __UINT64_C(0);
2816 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002817
2818 if (!str_restr && type->info.num.range) {
2819 str_restr = type->info.num.range->expr;
2820 }
2821 break;
2822 case LY_TYPE_UINT64:
2823 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002824 local_umin = __UINT64_C(0);
2825 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002826
2827 if (!str_restr && type->info.num.range) {
2828 str_restr = type->info.num.range->expr;
2829 }
2830 break;
2831 case LY_TYPE_STRING:
2832 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002833 local_umin = __UINT64_C(0);
2834 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835
2836 if (!str_restr && type->info.str.length) {
2837 str_restr = type->info.str.length->expr;
2838 }
2839 break;
2840 default:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002841 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002842 }
2843
2844 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002845 if (type->der) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002846 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002847 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002848 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002849 assert(!intv || (intv->kind == kind));
2850 }
2851
2852 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002853 /* we do not have any restriction, return superior ones */
2854 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002855 return EXIT_SUCCESS;
2856 }
2857
2858 /* adjust local min and max */
2859 if (intv) {
2860 tmp_intv = intv;
2861
2862 if (kind == 0) {
2863 local_umin = tmp_intv->value.uval.min;
2864 } else if (kind == 1) {
2865 local_smin = tmp_intv->value.sval.min;
2866 } else if (kind == 2) {
2867 local_fmin = tmp_intv->value.fval.min;
2868 }
2869
2870 while (tmp_intv->next) {
2871 tmp_intv = tmp_intv->next;
2872 }
2873
2874 if (kind == 0) {
2875 local_umax = tmp_intv->value.uval.max;
2876 } else if (kind == 1) {
2877 local_smax = tmp_intv->value.sval.max;
2878 } else if (kind == 2) {
2879 local_fmax = tmp_intv->value.fval.max;
2880 }
2881 }
2882
2883 /* finally parse our restriction */
2884 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002885 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002886 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002887 if (!tmp_local_intv) {
2888 assert(!local_intv);
2889 local_intv = malloc(sizeof *local_intv);
2890 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002891 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002892 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002893 tmp_local_intv = tmp_local_intv->next;
2894 }
Michal Vasko53b7da02018-02-13 15:28:42 +01002895 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002896
2897 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002898 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002899 tmp_local_intv->next = NULL;
2900
2901 /* min */
2902 ptr = seg_ptr;
2903 while (isspace(ptr[0])) {
2904 ++ptr;
2905 }
2906 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2907 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002908 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002909 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002910 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002911 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002912 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002913 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02002914 goto error;
2915 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002916 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002917 } else if (!strncmp(ptr, "min", 3)) {
2918 if (kind == 0) {
2919 tmp_local_intv->value.uval.min = local_umin;
2920 } else if (kind == 1) {
2921 tmp_local_intv->value.sval.min = local_smin;
2922 } else if (kind == 2) {
2923 tmp_local_intv->value.fval.min = local_fmin;
2924 }
2925
2926 ptr += 3;
2927 } else if (!strncmp(ptr, "max", 3)) {
2928 if (kind == 0) {
2929 tmp_local_intv->value.uval.min = local_umax;
2930 } else if (kind == 1) {
2931 tmp_local_intv->value.sval.min = local_smax;
2932 } else if (kind == 2) {
2933 tmp_local_intv->value.fval.min = local_fmax;
2934 }
2935
2936 ptr += 3;
2937 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002938 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002939 }
2940
2941 while (isspace(ptr[0])) {
2942 ptr++;
2943 }
2944
2945 /* no interval or interval */
2946 if ((ptr[0] == '|') || !ptr[0]) {
2947 if (kind == 0) {
2948 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2949 } else if (kind == 1) {
2950 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2951 } else if (kind == 2) {
2952 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2953 }
2954 } else if (!strncmp(ptr, "..", 2)) {
2955 /* skip ".." */
2956 ptr += 2;
2957 while (isspace(ptr[0])) {
2958 ++ptr;
2959 }
2960
2961 /* max */
2962 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2963 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02002964 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002965 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02002966 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002967 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002968 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002969 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02002970 goto error;
2971 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002972 }
2973 } else if (!strncmp(ptr, "max", 3)) {
2974 if (kind == 0) {
2975 tmp_local_intv->value.uval.max = local_umax;
2976 } else if (kind == 1) {
2977 tmp_local_intv->value.sval.max = local_smax;
2978 } else if (kind == 2) {
2979 tmp_local_intv->value.fval.max = local_fmax;
2980 }
2981 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002982 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002983 }
2984 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002985 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002986 }
2987
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002988 /* check min and max in correct order*/
2989 if (kind == 0) {
2990 /* current segment */
2991 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2992 goto error;
2993 }
2994 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2995 goto error;
2996 }
2997 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002998 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002999 goto error;
3000 }
3001 } else if (kind == 1) {
3002 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3003 goto error;
3004 }
3005 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3006 goto error;
3007 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003008 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003009 goto error;
3010 }
3011 } else if (kind == 2) {
3012 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3013 goto error;
3014 }
3015 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3016 goto error;
3017 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003018 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003019 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003020 goto error;
3021 }
3022 }
3023
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003024 /* next segment (next OR) */
3025 seg_ptr = strchr(seg_ptr, '|');
3026 if (!seg_ptr) {
3027 break;
3028 }
3029 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003030 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003031 }
3032
3033 /* check local restrictions against superior ones */
3034 if (intv) {
3035 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003036 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003037
3038 while (tmp_local_intv && tmp_intv) {
3039 /* reuse local variables */
3040 if (kind == 0) {
3041 local_umin = tmp_local_intv->value.uval.min;
3042 local_umax = tmp_local_intv->value.uval.max;
3043
3044 /* it must be in this interval */
3045 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3046 /* this interval is covered, next one */
3047 if (local_umax <= tmp_intv->value.uval.max) {
3048 tmp_local_intv = tmp_local_intv->next;
3049 continue;
3050 /* ascending order of restrictions -> fail */
3051 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003052 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003053 }
3054 }
3055 } else if (kind == 1) {
3056 local_smin = tmp_local_intv->value.sval.min;
3057 local_smax = tmp_local_intv->value.sval.max;
3058
3059 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3060 if (local_smax <= tmp_intv->value.sval.max) {
3061 tmp_local_intv = tmp_local_intv->next;
3062 continue;
3063 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003064 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003065 }
3066 }
3067 } else if (kind == 2) {
3068 local_fmin = tmp_local_intv->value.fval.min;
3069 local_fmax = tmp_local_intv->value.fval.max;
3070
Michal Vasko4d1f0482016-09-19 14:35:06 +02003071 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003072 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003073 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003074 tmp_local_intv = tmp_local_intv->next;
3075 continue;
3076 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003077 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003078 }
3079 }
3080 }
3081
3082 tmp_intv = tmp_intv->next;
3083 }
3084
3085 /* some interval left uncovered -> fail */
3086 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003087 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003088 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003089 }
3090
Michal Vaskoaeb51802016-04-11 10:58:47 +02003091 /* append the local intervals to all the intervals of the superior types, return it all */
3092 if (intv) {
3093 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3094 tmp_intv->next = local_intv;
3095 } else {
3096 intv = local_intv;
3097 }
3098 *ret = intv;
3099
3100 return EXIT_SUCCESS;
3101
3102error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003103 while (intv) {
3104 tmp_intv = intv->next;
3105 free(intv);
3106 intv = tmp_intv;
3107 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003108 while (local_intv) {
3109 tmp_local_intv = local_intv->next;
3110 free(local_intv);
3111 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003112 }
3113
Michal Vaskoaeb51802016-04-11 10:58:47 +02003114 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003115}
3116
Michal Vasko730dfdf2015-08-11 14:48:05 +02003117/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003118 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3119 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003120 *
3121 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003122 * @param[in] mod_name Typedef name module name.
3123 * @param[in] module Main module.
3124 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003125 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003126 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003127 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003128 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003129int
Michal Vasko1e62a092015-12-01 12:27:20 +01003130resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3131 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003132{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003133 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003134 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003135 int tpdf_size;
3136
Michal Vasko1dca6882015-10-22 14:29:42 +02003137 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138 /* no prefix, try built-in types */
3139 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003140 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003141 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003142 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003143 }
3144 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003145 }
3146 }
3147 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003148 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003149 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003150 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003151 }
3152 }
3153
Michal Vasko1dca6882015-10-22 14:29:42 +02003154 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003155 /* search in local typedefs */
3156 while (parent) {
3157 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003158 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003159 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3160 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003161 break;
3162
Radek Krejci76512572015-08-04 09:47:08 +02003163 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003164 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3165 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003166 break;
3167
Radek Krejci76512572015-08-04 09:47:08 +02003168 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003169 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3170 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003171 break;
3172
Radek Krejci76512572015-08-04 09:47:08 +02003173 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003174 case LYS_ACTION:
3175 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3176 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003177 break;
3178
Radek Krejci76512572015-08-04 09:47:08 +02003179 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003180 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3181 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182 break;
3183
Radek Krejci76512572015-08-04 09:47:08 +02003184 case LYS_INPUT:
3185 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003186 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3187 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003188 break;
3189
3190 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003191 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003192 continue;
3193 }
3194
3195 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003196 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003197 match = &tpdf[i];
3198 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003199 }
3200 }
3201
Michal Vaskodcf98e62016-05-05 17:53:53 +02003202 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203 }
Radek Krejcic071c542016-01-27 14:57:51 +01003204 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003206 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003207 if (!module) {
3208 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003209 }
3210 }
3211
3212 /* search in top level typedefs */
3213 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003214 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003215 match = &module->tpdf[i];
3216 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003217 }
3218 }
3219
3220 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003221 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003222 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003223 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 +02003224 match = &module->inc[i].submodule->tpdf[j];
3225 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003226 }
3227 }
3228 }
3229
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003230 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003231
3232check_leafref:
3233 if (ret) {
3234 *ret = match;
3235 }
3236 if (match->type.base == LY_TYPE_LEAFREF) {
3237 while (!match->type.info.lref.path) {
3238 match = match->type.der;
3239 assert(match);
3240 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003241 }
3242 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243}
3244
Michal Vasko1dca6882015-10-22 14:29:42 +02003245/**
3246 * @brief Check the default \p value of the \p type. Logs directly.
3247 *
3248 * @param[in] type Type definition to use.
3249 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003250 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003251 *
3252 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3253 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003254static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003255check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003256{
Radek Krejcibad2f172016-08-02 11:04:15 +02003257 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003258 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003259 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003260 char *s;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003261 int ret = EXIT_SUCCESS, r;
Michal Vasko53b7da02018-02-13 15:28:42 +01003262 struct ly_ctx *ctx = module->ctx;
Michal Vasko1dca6882015-10-22 14:29:42 +02003263
Radek Krejci51673202016-11-01 17:00:32 +01003264 assert(value);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003265 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003266
Radek Krejcic13db382016-08-16 10:52:42 +02003267 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003268 /* the type was not resolved yet, nothing to do for now */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003269 ret = EXIT_FAILURE;
3270 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003271 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003272 /* do not check defaults in not implemented module's data */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003273 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003274 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003275 /* identityrefs are checked when instantiated in data instead of typedef,
3276 * but in typedef the value has to be modified to include the prefix */
3277 if (*value) {
3278 if (strchr(*value, ':')) {
3279 dflt = transform_schema2json(module, *value);
3280 } else {
3281 /* default prefix of the module where the typedef is defined */
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003282 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3283 LOGMEM(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003284 ret = -1;
3285 goto cleanup;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003286 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003287 dflt = lydict_insert_zc(ctx, s);
Radek Krejci9e6af732017-04-27 14:40:25 +02003288 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003289 lydict_remove(ctx, *value);
Radek Krejci9e6af732017-04-27 14:40:25 +02003290 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003291 dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003292 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003293 goto cleanup;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003294 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3295 /* leafref in typedef cannot be checked */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003296 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003297 }
3298
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003299 dflt = lydict_insert(ctx, *value, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003300 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003301 /* we do not have a new default value, so is there any to check even, in some base type? */
3302 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3303 if (base_tpdf->dflt) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003304 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
Michal Vasko478c4652016-07-21 12:55:01 +02003305 break;
3306 }
3307 }
3308
Radek Krejci51673202016-11-01 17:00:32 +01003309 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003310 /* no default value, nothing to check, all is well */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003311 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003312 }
3313
3314 /* 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)? */
3315 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003316 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003317 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003318 goto cleanup;
Radek Krejci9e6af732017-04-27 14:40:25 +02003319 } else {
3320 /* check the default value from typedef, but use also the typedef's module
3321 * due to possible searching in imported modules which is expected in
3322 * typedef's module instead of module where the typedef is used */
3323 module = base_tpdf->module;
3324 }
3325 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003326 case LY_TYPE_INST:
3327 case LY_TYPE_LEAFREF:
3328 case LY_TYPE_BOOL:
3329 case LY_TYPE_EMPTY:
3330 /* 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 +01003331 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003332 case LY_TYPE_BITS:
3333 /* the default value must match the restricted list of values, if the type was restricted */
3334 if (type->info.bits.count) {
3335 break;
3336 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003337 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003338 case LY_TYPE_ENUM:
3339 /* the default value must match the restricted list of values, if the type was restricted */
3340 if (type->info.enums.count) {
3341 break;
3342 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003343 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003344 case LY_TYPE_DEC64:
3345 if (type->info.dec64.range) {
3346 break;
3347 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003348 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003349 case LY_TYPE_BINARY:
3350 if (type->info.binary.length) {
3351 break;
3352 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003353 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003354 case LY_TYPE_INT8:
3355 case LY_TYPE_INT16:
3356 case LY_TYPE_INT32:
3357 case LY_TYPE_INT64:
3358 case LY_TYPE_UINT8:
3359 case LY_TYPE_UINT16:
3360 case LY_TYPE_UINT32:
3361 case LY_TYPE_UINT64:
3362 if (type->info.num.range) {
3363 break;
3364 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003365 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003366 case LY_TYPE_STRING:
3367 if (type->info.str.length || type->info.str.patterns) {
3368 break;
3369 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003370 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003371 case LY_TYPE_UNION:
3372 /* way too much trouble learning whether we need to check the default again, so just do it */
3373 break;
3374 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01003375 LOGINT(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003376 ret = -1;
3377 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003378 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003379 } else if (type->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003380 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3381 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003382 ret = -1;
3383 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003384 }
3385
Michal Vasko1dca6882015-10-22 14:29:42 +02003386 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003387 memset(&node, 0, sizeof node);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003388 node.value_str = lydict_insert(ctx, dflt, 0);
Michal Vasko1dca6882015-10-22 14:29:42 +02003389 node.value_type = type->base;
Michal Vasko31a2d322018-01-12 13:36:12 +01003390
3391 if (tpdf) {
3392 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003393 if (!node.schema) {
3394 LOGMEM(ctx);
3395 ret = -1;
3396 goto cleanup;
3397 }
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003398 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003399 if (r == -1) {
3400 LOGMEM(ctx);
3401 ret = -1;
3402 goto cleanup;
3403 }
Michal Vasko31a2d322018-01-12 13:36:12 +01003404 node.schema->module = module;
3405 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3406 } else {
3407 node.schema = (struct lys_node *)type->parent;
3408 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003409
Radek Krejci37b756f2016-01-18 10:15:03 +01003410 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003411 if (!type->info.lref.target) {
3412 ret = EXIT_FAILURE;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003413 goto cleanup;
Michal Vasko1dca6882015-10-22 14:29:42 +02003414 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003415 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003416 if (!ret) {
3417 /* adopt possibly changed default value to its canonical form */
3418 if (*value) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003419 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003420 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003421 dflt = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003422 }
3423 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003424 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01003425 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003426 /* possible forward reference */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003427 ret = EXIT_FAILURE;
Radek Krejcibad2f172016-08-02 11:04:15 +02003428 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003429 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003430 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3431 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3432 /* we have refined bits/enums */
Michal Vasko53b7da02018-02-13 15:28:42 +01003433 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
Radek Krejcibad2f172016-08-02 11:04:15 +02003434 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003435 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003436 }
3437 }
Radek Krejci51673202016-11-01 17:00:32 +01003438 } else {
3439 /* success - adopt canonical form from the node into the default value */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003440 if (!ly_strequal(dflt, node.value_str, 1)) {
Radek Krejci51673202016-11-01 17:00:32 +01003441 /* this can happen only if we have non-inherited default value,
3442 * inherited default values are already in canonical form */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003443 assert(ly_strequal(dflt, *value, 1));
3444
3445 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003446 *value = node.value_str;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003447 node.value_str = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003448 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003449 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003450 }
3451
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003452cleanup:
Michal Vasko70bf8e52018-03-26 11:32:33 +02003453 lyd_free_value(node.value, node.value_type, node.value_flags, type);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003454 lydict_remove(ctx, node.value_str);
3455 if (tpdf && node.schema) {
Michal Vasko31a2d322018-01-12 13:36:12 +01003456 free((char *)node.schema->name);
3457 free(node.schema);
3458 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003459 lydict_remove(ctx, dflt);
Michal Vasko1dca6882015-10-22 14:29:42 +02003460
3461 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003462}
3463
Michal Vasko730dfdf2015-08-11 14:48:05 +02003464/**
3465 * @brief Check a key for mandatory attributes. Logs directly.
3466 *
3467 * @param[in] key The key to check.
3468 * @param[in] flags What flags to check.
3469 * @param[in] list The list of all the keys.
3470 * @param[in] index Index of the key in the key list.
3471 * @param[in] name The name of the keys.
3472 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003473 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003474 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003475 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003476static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003477check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478{
Radek Krejciadb57612016-02-16 13:34:34 +01003479 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480 char *dup = NULL;
3481 int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01003482 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483
3484 /* existence */
3485 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003486 if (name[len] != '\0') {
3487 dup = strdup(name);
Michal Vasko53b7da02018-02-13 15:28:42 +01003488 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003489 dup[len] = '\0';
3490 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003491 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003492 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003493 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003494 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495 }
3496
3497 /* uniqueness */
3498 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003499 if (key == list->keys[j]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003500 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003501 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003502 }
3503 }
3504
3505 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003506 if (key->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003507 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003508 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003509 }
3510
3511 /* type of the leaf is not built-in empty */
Radek Krejci13fde922018-05-16 10:45:58 +02003512 if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003513 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003514 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003515 }
3516
3517 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003518 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003519 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003520 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003521 }
3522
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003523 /* key is not placed from augment */
3524 if (key->parent->nodetype == LYS_AUGMENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003525 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3526 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003527 return -1;
3528 }
3529
Radek Krejci3f21ada2016-08-01 13:34:31 +02003530 /* key is not when/if-feature -conditional */
3531 j = 0;
3532 if (key->when || (key->iffeature_size && (j = 1))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003533 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3534 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003535 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003536 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003537 }
3538
Michal Vasko0b85aa82016-03-07 14:37:43 +01003539 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003540}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003541
3542/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003543 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003544 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003546 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547 *
3548 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3549 */
3550int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003551resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552{
Radek Krejci581ce772015-11-10 17:22:40 +01003553 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003554 const struct lys_node *leaf = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01003555 struct ly_ctx *ctx = parent->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003556
Michal Vaskodc300b02017-04-07 14:09:20 +02003557 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003558 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003559 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003560 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003561 if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003562 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 +02003563 } else if (rc == -2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003564 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003565 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003566 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003567 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003568 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3569 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003570 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003571 }
Radek Krejci581ce772015-11-10 17:22:40 +01003572 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003574 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003575 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3576 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003577 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578 }
3579
Radek Krejcicf509982015-12-15 09:22:44 +01003580 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003581 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3582 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003583 return -1;
3584 }
3585
Radek Krejcid09d1a52016-08-11 14:05:45 +02003586 /* check that all unique's targets are of the same config type */
3587 if (*trg_type) {
3588 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003589 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3590 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003591 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3592 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3593 return -1;
3594 }
3595 } else {
3596 /* first unique */
3597 if (leaf->flags & LYS_CONFIG_W) {
3598 *trg_type = 1;
3599 } else {
3600 *trg_type = 2;
3601 }
3602 }
3603
Radek Krejcica7efb72016-01-18 13:06:01 +01003604 /* set leaf's unique flag */
3605 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3606
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003607 return EXIT_SUCCESS;
3608
3609error:
3610
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003611 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003612}
3613
Radek Krejci0c0086a2016-03-24 15:20:28 +01003614void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003615unres_data_del(struct unres_data *unres, uint32_t i)
3616{
3617 /* there are items after the one deleted */
3618 if (i+1 < unres->count) {
3619 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003620 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003621
3622 /* deleting the last item */
3623 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003624 free(unres->node);
3625 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003626 }
3627
3628 /* if there are no items after and it is not the last one, just move the counter */
3629 --unres->count;
3630}
3631
Michal Vasko0491ab32015-08-19 14:28:29 +02003632/**
3633 * @brief Resolve (find) a data node from a specific module. Does not log.
3634 *
3635 * @param[in] mod Module to search in.
3636 * @param[in] name Name of the data node.
3637 * @param[in] nam_len Length of the name.
3638 * @param[in] start Data node to start the search from.
3639 * @param[in,out] parents Resolved nodes. If there are some parents,
3640 * they are replaced (!!) with the resolvents.
3641 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003642 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003643 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003644static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003645resolve_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 +02003646{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003647 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003648 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003649 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003650
Michal Vasko23b61ec2015-08-19 11:19:50 +02003651 if (!parents->count) {
3652 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003653 parents->node = malloc(sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003654 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003655 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003656 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003657 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003658 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003659 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003660 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003661 continue;
3662 }
3663 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003664 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003665 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003666 && node->schema->name[nam_len] == '\0') {
3667 /* matching target */
3668 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003669 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003670 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003671 flag = 1;
3672 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003673 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003674 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003675 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003676 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003677 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003678 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679 }
3680 }
3681 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003682
3683 if (!flag) {
3684 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003685 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003686 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003687 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003688 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003689 }
3690
Michal Vasko0491ab32015-08-19 14:28:29 +02003691 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003692}
3693
Michal Vaskoe27516a2016-10-10 17:55:31 +00003694static int
Michal Vasko1c007172017-03-10 10:20:44 +01003695resolve_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 +00003696{
3697 int dep1, dep2;
3698 const struct lys_node *node;
3699
3700 if (lys_parent(op_node)) {
3701 /* inner operation (notif/action) */
3702 if (abs_path) {
3703 return 1;
3704 } else {
3705 /* compare depth of both nodes */
3706 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3707 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3708 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3709 return 1;
3710 }
3711 }
3712 } else {
3713 /* top-level operation (notif/rpc) */
3714 if (op_node != first_node) {
3715 return 1;
3716 }
3717 }
3718
3719 return 0;
3720}
3721
Michal Vasko730dfdf2015-08-11 14:48:05 +02003722/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003723 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003724 *
Michal Vaskobb211122015-08-19 14:03:11 +02003725 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003726 * @param[in] context_node Predicate context node (where the predicate is placed).
3727 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003728 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003729 *
Michal Vasko184521f2015-09-24 13:14:26 +02003730 * @return 0 on forward reference, otherwise the number
3731 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003732 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003733 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003734static int
Michal Vasko1c007172017-03-10 10:20:44 +01003735resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3736 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003737{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003738 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003739 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003740 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003741 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3742 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003743 struct ly_ctx *ctx = context_node->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003744
3745 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003746 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003747 &pke_len, &has_predicate)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003748 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003749 return -parsed+i;
3750 }
3751 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003752 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003753
Michal Vasko58090902015-08-13 14:04:15 +02003754 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003755 if (sour_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003756 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003757 } else {
3758 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003759 }
Michal Vaskobb520442017-05-23 10:55:18 +02003760 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003761 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003762 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003763 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 }
3765
3766 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003767 dest_parent_times = 0;
3768 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003769 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3770 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003771 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 return -parsed;
3773 }
3774 pke_parsed += i;
3775
Radek Krejciadb57612016-02-16 13:34:34 +01003776 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003777 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3778 && !((struct lys_node_augment *)dst_node->parent)->target) {
3779 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003780 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003781 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3782 return 0;
3783 }
3784
Michal Vaskofbaead72016-10-07 10:54:48 +02003785 /* path is supposed to be evaluated in data tree, so we have to skip
3786 * all schema nodes that cannot be instantiated in data tree */
3787 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003788 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003789 dst_node = lys_parent(dst_node));
3790
Michal Vasko1f76a282015-08-04 16:16:53 +02003791 if (!dst_node) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003792 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003793 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003794 }
3795 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003796 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003797 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003798 if (dest_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003799 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003800 } else {
3801 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003802 }
Michal Vaskobb520442017-05-23 10:55:18 +02003803 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 +02003804 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003805 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003806 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003807 }
3808
Michal Vaskoe27516a2016-10-10 17:55:31 +00003809 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003810 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003811 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003812 }
3813 first_iter = 0;
3814 }
3815
Michal Vasko1f76a282015-08-04 16:16:53 +02003816 if (pke_len == pke_parsed) {
3817 break;
3818 }
3819
Michal Vaskobb520442017-05-23 10:55:18 +02003820 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 +02003821 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003822 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003823 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003824 return -parsed;
3825 }
3826 pke_parsed += i;
3827 }
3828
3829 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003830 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003831 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
Michal Vasko53b7da02018-02-13 15:28:42 +01003832 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003833 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003834 return -parsed;
3835 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003836 } while (has_predicate);
3837
3838 return parsed;
3839}
3840
Michal Vasko730dfdf2015-08-11 14:48:05 +02003841/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003842 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003843 *
Michal Vaskobb211122015-08-19 14:03:11 +02003844 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003845 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003846 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003847 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003848 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003849 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003850static int
Michal Vasko1c007172017-03-10 10:20:44 +01003851resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003852{
Michal Vaskocb45f472018-02-12 10:47:42 +01003853 const struct lys_node *node, *op_node = NULL, *tmp_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02003854 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003855 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02003856 const char *id, *prefix, *name;
3857 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskocb45f472018-02-12 10:47:42 +01003858 int i, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003859 struct ly_ctx *ctx = parent->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003860
Michal Vasko184521f2015-09-24 13:14:26 +02003861 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003862 parent_times = 0;
3863 id = path;
3864
Michal Vasko1c007172017-03-10 10:20:44 +01003865 /* find operation schema we are in */
3866 for (op_node = lys_parent(parent);
3867 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3868 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003869
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003870 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003871 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003872 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 +01003873 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003874 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003875 }
3876 id += i;
3877
Michal Vaskobb520442017-05-23 10:55:18 +02003878 /* get the current module */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003879 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003880 if (!tmp_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003881 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vaskobb520442017-05-23 10:55:18 +02003882 return EXIT_FAILURE;
3883 }
3884 last_aug = NULL;
3885
Michal Vasko184521f2015-09-24 13:14:26 +02003886 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003887 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003888 /* use module data */
3889 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003890
Michal Vasko1f76a282015-08-04 16:16:53 +02003891 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003892 /* we are looking for the right parent */
3893 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003894 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
3895 && !((struct lys_node_augment *)node->parent)->target) {
3896 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003897 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003898 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
3899 return EXIT_FAILURE;
3900 }
3901
Radek Krejci3a5501d2016-07-18 22:03:34 +02003902 /* path is supposed to be evaluated in data tree, so we have to skip
3903 * all schema nodes that cannot be instantiated in data tree */
3904 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003905 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003906 node = lys_parent(node));
3907
Michal Vasko1f76a282015-08-04 16:16:53 +02003908 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003909 if (i == parent_times - 1) {
3910 /* top-level */
3911 break;
3912 }
3913
3914 /* higher than top-level */
Michal Vasko53b7da02018-02-13 15:28:42 +01003915 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003916 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003917 }
3918 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003919 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003920 LOGINT(ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003921 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003922 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003923 }
3924
Michal Vaskobb520442017-05-23 10:55:18 +02003925 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3926 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003927 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003928get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003929 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02003930 }
3931
Michal Vaskocb45f472018-02-12 10:47:42 +01003932 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
3933 node = NULL;
3934 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
3935 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
3936 continue;
3937 }
3938 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
3939 continue;
3940 }
3941 /* match */
3942 break;
3943 }
3944 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003945 if (last_aug) {
Michal Vaskob6906872018-03-12 11:35:09 +01003946 /* restore the correct augment target */
3947 node = last_aug->target;
Michal Vaskobb520442017-05-23 10:55:18 +02003948 goto get_next_augment;
3949 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003950 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003951 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003952 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003953
Michal Vaskoe27516a2016-10-10 17:55:31 +00003954 if (first_iter) {
3955 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003956 if (op_node && parent_times &&
3957 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003958 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003959 }
3960 first_iter = 0;
3961 }
3962
Michal Vasko1f76a282015-08-04 16:16:53 +02003963 if (has_predicate) {
3964 /* we have predicate, so the current result must be list */
3965 if (node->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003966 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003967 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003968 }
3969
Michal Vasko1c007172017-03-10 10:20:44 +01003970 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003971 if (!i) {
3972 return EXIT_FAILURE;
3973 } else if (i < 0) {
3974 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003975 }
3976 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003977 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003978 }
3979 } while (id[0]);
3980
Michal Vaskoca917682016-07-25 11:00:37 +02003981 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003982 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003983 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3984 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 +02003985 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003986 }
3987
Radek Krejcicf509982015-12-15 09:22:44 +01003988 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003989 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003990 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003991 return -1;
3992 }
3993
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003994 if (ret) {
3995 *ret = node;
3996 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003997
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003998 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003999}
4000
Michal Vasko730dfdf2015-08-11 14:48:05 +02004001/**
Michal Vasko718ecdd2017-10-03 14:12:39 +02004002 * @brief Compare 2 data node values.
4003 *
4004 * Comparison performed on canonical forms, the first value
4005 * is first transformed into canonical form.
4006 *
4007 * @param[in] node Leaf/leaf-list with these values.
4008 * @param[in] noncan_val Non-canonical value.
4009 * @param[in] noncan_val_len Length of \p noncal_val.
4010 * @param[in] can_val Canonical value.
4011 * @return 1 if equal, 0 if not, -1 on error (logged).
4012 */
4013static int
4014valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4015{
4016 int ret;
4017 struct lyd_node_leaf_list leaf;
4018 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4019
4020 /* dummy leaf */
4021 memset(&leaf, 0, sizeof leaf);
4022 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4023
4024repeat:
4025 leaf.value_type = sleaf->type.base;
4026 leaf.schema = node;
4027
4028 if (leaf.value_type == LY_TYPE_LEAFREF) {
4029 if (!sleaf->type.info.lref.target) {
4030 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01004031 LOGINT(node->module->ctx);
Michal Vasko718ecdd2017-10-03 14:12:39 +02004032 ret = -1;
4033 goto finish;
4034 }
4035 sleaf = sleaf->type.info.lref.target;
4036 goto repeat;
4037 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01004038 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
Michal Vasko718ecdd2017-10-03 14:12:39 +02004039 ret = -1;
4040 goto finish;
4041 }
4042 }
4043
4044 if (!strcmp(leaf.value_str, can_val)) {
4045 ret = 1;
4046 } else {
4047 ret = 0;
4048 }
4049
4050finish:
4051 lydict_remove(node->module->ctx, leaf.value_str);
4052 return ret;
4053}
4054
4055/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004056 * @brief Resolve instance-identifier predicate in JSON data format.
4057 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004058 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02004059 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02004060 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004061 * @param[in,out] node Node matching the restriction without
4062 * the predicate. If it does not satisfy the predicate,
4063 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004064 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004065 * @return Number of characters successfully parsed,
4066 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004067 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004068static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004069resolve_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 +02004070{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004071 /* ... /node[key=value] ... */
4072 struct lyd_node_leaf_list *key;
4073 struct lys_node_leaf **list_keys = NULL;
Michal Vaskoab8adcd2017-10-02 13:32:24 +02004074 struct lys_node_list *slist = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004075 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004076 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vasko53b7da02018-02-13 15:28:42 +01004077 struct ly_ctx *ctx = prev_mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004078
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004079 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02004080
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004081 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004082 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004083 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4084 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004085 }
4086 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004087
Michal Vasko88850b72017-10-02 13:13:21 +02004088 if (!(*node)) {
4089 /* just parse it all */
4090 continue;
4091 }
4092
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004093 /* target */
4094 if (name[0] == '.') {
4095 /* leaf-list value */
4096 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004097 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004098 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4099 parsed = -1;
4100 goto cleanup;
4101 }
4102
4103 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004104 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004105 *node = NULL;
4106 goto cleanup;
4107 }
4108
4109 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004110 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004111
4112 /* keyless list position */
4113 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004114 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004115 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4116 parsed = -1;
4117 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004118 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004119
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004120 if (((struct lys_node_list *)(*node)->schema)->keys) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004121 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 +02004122 (*node)->schema->name);
4123 parsed = -1;
4124 goto cleanup;
4125 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004126
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004127 /* check the index */
4128 if (atoi(name) != cur_idx) {
4129 *node = NULL;
4130 goto cleanup;
4131 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004132
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004133 } else {
4134 /* list key value */
4135 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004136 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004137 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4138 parsed = -1;
4139 goto cleanup;
4140 }
4141 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004142
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004143 /* prepare key array */
4144 if (!list_keys) {
4145 list_keys = malloc(slist->keys_size * sizeof *list_keys);
Michal Vasko53b7da02018-02-13 15:28:42 +01004146 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004147 for (i = 0; i < slist->keys_size; ++i) {
4148 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02004149 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004150 }
4151
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004152 /* find the schema key leaf */
4153 for (i = 0; i < slist->keys_size; ++i) {
4154 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4155 break;
4156 }
4157 }
4158 if (i == slist->keys_size) {
4159 /* this list has no such key */
Michal Vasko53b7da02018-02-13 15:28:42 +01004160 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004161 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4162 parsed = -1;
4163 goto cleanup;
4164 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004165
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004166 /* check module */
4167 if (model) {
4168 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004169 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 +02004170 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4171 parsed = -1;
4172 goto cleanup;
4173 }
4174 } else {
4175 if (list_keys[i]->module != prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004176 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 +02004177 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4178 parsed = -1;
4179 goto cleanup;
4180 }
4181 }
4182
4183 /* find the actual data key */
4184 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4185 if (key->schema == (struct lys_node *)list_keys[i]) {
4186 break;
4187 }
4188 }
4189 if (!key) {
4190 /* list instance is missing a key? definitely should not happen */
Michal Vasko53b7da02018-02-13 15:28:42 +01004191 LOGINT(ctx);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004192 parsed = -1;
4193 goto cleanup;
4194 }
4195
4196 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004197 if (!valequal(key->schema, value, val_len, key->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004198 *node = NULL;
Michal Vasko88850b72017-10-02 13:13:21 +02004199 /* we still want to parse the whole predicate */
4200 continue;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004201 }
4202
4203 /* everything is fine, mark this key as resolved */
4204 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004205 }
4206 } while (has_predicate);
4207
Michal Vaskob2f40be2016-09-08 16:03:48 +02004208 /* check that all list keys were specified */
Michal Vasko88850b72017-10-02 13:13:21 +02004209 if (*node && list_keys) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004210 for (i = 0; i < slist->keys_size; ++i) {
4211 if (list_keys[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004212 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 +02004213 parsed = -1;
4214 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004215 }
4216 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004217 }
4218
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004219cleanup:
4220 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221 return parsed;
4222}
4223
Michal Vasko895c11f2018-03-12 11:35:58 +01004224static int
4225check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004226{
Michal Vasko0b963112017-08-11 12:45:36 +02004227 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004228 struct lyxp_set set;
Michal Vasko895c11f2018-03-12 11:35:58 +01004229 enum int_log_opts prev_ilo;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004230
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004231 if (check_place) {
4232 parent = node;
4233 while (parent) {
4234 if (parent->nodetype == LYS_GROUPING) {
4235 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004236 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004237 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004238 if (parent->nodetype == LYS_AUGMENT) {
4239 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004240 /* unresolved augment, skip for now (will be checked later) */
4241 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004242 } else {
4243 parent = ((struct lys_node_augment *)parent)->target;
4244 continue;
4245 }
4246 }
4247 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004248 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004249 }
4250
Michal Vasko895c11f2018-03-12 11:35:58 +01004251 memset(&set, 0, sizeof set);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004252
Michal Vasko895c11f2018-03-12 11:35:58 +01004253 /* produce just warnings */
4254 ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4255 lyxp_node_atomize(node, &set, 1);
4256 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4257
4258 if (set.val.snodes) {
4259 free(set.val.snodes);
4260 }
4261 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004262}
4263
Radek Krejcif71f48f2016-10-25 16:37:24 +02004264static int
4265check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4266{
Radek Krejcidce5f972017-09-12 15:47:49 +02004267 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004268
4269 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004270 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4271 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004272 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 +02004273 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4274 return -1;
4275 }
4276 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4277 * of leafref resolving (lys_leaf_add_leafref_target()) */
4278 } else if (type->base == LY_TYPE_UNION) {
4279 for (i = 0; i < type->info.uni.count; i++) {
4280 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4281 return -1;
4282 }
4283 }
4284 }
4285 return 0;
4286}
4287
Michal Vasko9e635ac2016-10-17 11:44:09 +02004288/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004289 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004290 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004291 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004292 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004293 * @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 +02004294 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004295 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004296 *
4297 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004298 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004299int
4300inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004301{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004302 struct lys_node_leaf *leaf;
Michal Vasko53b7da02018-02-13 15:28:42 +01004303 struct ly_ctx *ctx;
4304
4305 if (!node) {
4306 return 0;
4307 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004308
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004309 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Michal Vasko53b7da02018-02-13 15:28:42 +01004310 ctx = node->module->ctx;
4311
Radek Krejci1d82ef62015-08-07 14:44:40 +02004312 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004313 if (clear) {
4314 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004315 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004316 } else {
4317 if (node->flags & LYS_CONFIG_SET) {
4318 /* skip nodes with an explicit config value */
4319 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004320 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4321 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004322 return -1;
4323 }
4324 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004325 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004326
4327 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4328 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4329 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004330 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4331 && !((struct lys_node_list *)node)->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004332 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
Michal Vaskoe022a562016-09-27 14:24:15 +02004333 return -1;
4334 }
4335 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004336 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004337 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004338 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004339 return -1;
4340 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004341 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4342 leaf = (struct lys_node_leaf *)node;
4343 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004344 return -1;
4345 }
4346 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004347 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004348
4349 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004350}
4351
Michal Vasko730dfdf2015-08-11 14:48:05 +02004352/**
Michal Vasko7178e692016-02-12 15:58:05 +01004353 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004354 *
Michal Vaskobb211122015-08-19 14:03:11 +02004355 * @param[in] aug Augment to use.
Michal Vasko97234262018-02-01 09:53:01 +01004356 * @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 +01004357 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004358 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004359 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004360 */
Michal Vasko7178e692016-02-12 15:58:05 +01004361static int
Michal Vasko97234262018-02-01 09:53:01 +01004362resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004363{
Michal Vasko44ab1462017-05-18 13:18:36 +02004364 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004365 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004366 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004367 struct ly_set *set;
Michal Vasko53b7da02018-02-13 15:28:42 +01004368 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004369
Michal Vasko2ef7db62017-06-12 09:24:02 +02004370 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004371 mod = lys_main_module(aug->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01004372 ctx = mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004373
Michal Vaskobb520442017-05-23 10:55:18 +02004374 /* set it as not applied for now */
4375 aug->flags |= LYS_NOTAPPLIED;
4376
Michal Vasko2ef7db62017-06-12 09:24:02 +02004377 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004378 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004379 /* resolve target node */
Michal Vasko97234262018-02-01 09:53:01 +01004380 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 +02004381 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004382 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004383 return -1;
4384 }
Michal Vasko50576712017-07-28 12:28:33 +02004385 if (!set) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004386 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004387 return EXIT_FAILURE;
4388 }
Michal Vasko50576712017-07-28 12:28:33 +02004389 aug->target = set->set.s[0];
4390 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004391 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004392
Michal Vaskod58d5962016-03-02 14:29:41 +01004393 /* check for mandatory nodes - if the target node is in another module
4394 * the added nodes cannot be mandatory
4395 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004396 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4397 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004398 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004399 }
4400
Michal Vasko07e89ef2016-03-03 13:28:57 +01004401 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004402 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004403 LY_TREE_FOR(aug->child, sub) {
4404 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4405 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004406 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4407 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004408 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004409 return -1;
4410 }
4411 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004412 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004413 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004414 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004415 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4416 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004417 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004418 return -1;
4419 }
4420 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004421 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004422 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004423 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004424 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4425 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004426 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004427 return -1;
4428 }
4429 }
4430 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004431 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4432 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 +01004433 return -1;
4434 }
4435
Radek Krejcic071c542016-01-27 14:57:51 +01004436 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004437 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004438 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004439 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004440 }
4441 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004442
Michal Vasko44ab1462017-05-18 13:18:36 +02004443 if (!aug->child) {
4444 /* empty augment, nothing to connect, but it is techincally applied */
Michal Vasko53b7da02018-02-13 15:28:42 +01004445 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
Michal Vasko44ab1462017-05-18 13:18:36 +02004446 aug->flags &= ~LYS_NOTAPPLIED;
Radek Krejciaa6b2a12017-10-26 15:52:39 +02004447 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4448 /* we try to connect the augment only in case the module is implemented or
4449 * the augment applies on the used grouping, anyway we failed here */
Michal Vasko44ab1462017-05-18 13:18:36 +02004450 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004451 }
4452
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004453 return EXIT_SUCCESS;
4454}
4455
Radek Krejcie534c132016-11-23 13:32:31 +01004456static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004457resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004458{
4459 enum LY_VLOG_ELEM vlog_type;
4460 void *vlog_node;
4461 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004462 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004463 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004464 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004465 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004466 struct lys_ext_instance *tmp_ext;
Michal Vasko53b7da02018-02-13 15:28:42 +01004467 struct ly_ctx *ctx = NULL;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004468 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004469
4470 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004471 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004472 vlog_node = info->parent;
4473 vlog_type = LY_VLOG_LYS;
4474 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004475 case LYEXT_PAR_MODULE:
4476 case LYEXT_PAR_IMPORT:
4477 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004478 vlog_node = NULL;
4479 vlog_type = LY_VLOG_LYS;
4480 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004481 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004482 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004483 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004484 break;
4485 }
4486
4487 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004488 /* YIN */
4489
Radek Krejcie534c132016-11-23 13:32:31 +01004490 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004491 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004492 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004493 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004494 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004495 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004496 ctx = mod->ctx;
Radek Krejcie534c132016-11-23 13:32:31 +01004497
4498 /* find the extension definition */
4499 e = NULL;
4500 for (i = 0; i < mod->extensions_size; i++) {
4501 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4502 e = &mod->extensions[i];
4503 break;
4504 }
4505 }
4506 /* try submodules */
4507 for (j = 0; !e && j < mod->inc_size; j++) {
4508 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4509 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4510 e = &mod->inc[j].submodule->extensions[i];
4511 break;
4512 }
4513 }
4514 }
4515 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004516 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004517 return EXIT_FAILURE;
4518 }
4519
4520 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004521
Radek Krejci72b35992017-01-04 16:27:44 +01004522 if (e->plugin && e->plugin->check_position) {
4523 /* common part - we have plugin with position checking function, use it first */
4524 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4525 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004526 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004527 return -1;
4528 }
4529 }
4530
Radek Krejci8d6b7422017-02-03 14:42:13 +01004531 /* extension type-specific part - allocation */
4532 if (e->plugin) {
4533 etype = e->plugin->type;
4534 } else {
4535 /* default type */
4536 etype = LYEXT_FLAG;
4537 }
4538 switch (etype) {
4539 case LYEXT_FLAG:
4540 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4541 break;
4542 case LYEXT_COMPLEX:
4543 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4544 break;
4545 case LYEXT_ERR:
4546 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004547 LOGINT(ctx);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004548 return -1;
4549 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004550 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004551
4552 /* common part for all extension types */
4553 (*ext)->def = e;
4554 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004555 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004556 (*ext)->insubstmt = info->substmt;
4557 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004558 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004559 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004560
PavolVicand86b0d62017-09-01 11:01:39 +02004561 if (e->argument) {
4562 if (!(e->flags & LYS_YINELEM)) {
4563 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4564 if (!(*ext)->arg_value) {
PavolVicane7a1fc62018-02-19 16:50:27 +01004565 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
PavolVicand86b0d62017-09-01 11:01:39 +02004566 return -1;
4567 }
4568
4569 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4570 } else {
4571 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4572 if (ly_strequal(yin->name, e->argument, 1)) {
4573 (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
4574 lyxml_free(mod->ctx, yin);
4575 break;
4576 }
4577 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004578 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004579 }
4580
PavolVican92f23622017-12-12 13:35:56 +01004581 if ((*ext)->flags & LYEXT_OPT_VALID &&
4582 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004583 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004584 }
4585
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004586 (*ext)->nodetype = LYS_EXT;
4587 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004588
Radek Krejci8d6b7422017-02-03 14:42:13 +01004589 /* extension type-specific part - parsing content */
4590 switch (etype) {
4591 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004592 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4593 if (!yin->ns) {
4594 /* garbage */
4595 lyxml_free(mod->ctx, yin);
4596 continue;
4597 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4598 /* standard YANG statements are not expected here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004599 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004600 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004601 } else if (yin->ns == info->data.yin->ns &&
4602 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004603 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004604 if ((*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004605 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004606 return -1;
4607 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004608 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004609 yin->content = NULL;
4610 lyxml_free(mod->ctx, yin);
4611 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004612 /* extension instance */
4613 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4614 LYEXT_SUBSTMT_SELF, 0, unres)) {
4615 return -1;
4616 }
Radek Krejci72b35992017-01-04 16:27:44 +01004617
Radek Krejci72b35992017-01-04 16:27:44 +01004618 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004619 }
Radek Krejci72b35992017-01-04 16:27:44 +01004620 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004621 break;
4622 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004623 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004624 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4625 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004626 return -1;
4627 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004628 break;
4629 default:
4630 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004631 }
Radek Krejci72b35992017-01-04 16:27:44 +01004632
4633 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4634
Radek Krejcie534c132016-11-23 13:32:31 +01004635 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004636 /* YANG */
4637
PavolVicanc1807262017-01-31 18:00:27 +01004638 ext_prefix = (char *)(*ext)->def;
4639 tmp = strchr(ext_prefix, ':');
4640 if (!tmp) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004641 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004642 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004643 }
4644 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004645
PavolVicanc1807262017-01-31 18:00:27 +01004646 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004647 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
PavolVicanc1807262017-01-31 18:00:27 +01004648 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004649 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004650 return EXIT_FAILURE;
4651 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004652 ctx = mod->ctx;
PavolVicanc1807262017-01-31 18:00:27 +01004653
4654 /* find the extension definition */
4655 e = NULL;
4656 for (i = 0; i < mod->extensions_size; i++) {
4657 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4658 e = &mod->extensions[i];
4659 break;
4660 }
4661 }
4662 /* try submodules */
4663 for (j = 0; !e && j < mod->inc_size; j++) {
4664 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4665 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4666 e = &mod->inc[j].submodule->extensions[i];
4667 break;
4668 }
4669 }
4670 }
4671 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004672 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004673 return EXIT_FAILURE;
4674 }
4675
PavolVicanfcc98762017-09-01 15:51:39 +02004676 (*ext)->flags &= ~LYEXT_OPT_YANG;
4677 (*ext)->def = NULL;
4678
PavolVicanc1807262017-01-31 18:00:27 +01004679 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4680
4681 if (e->plugin && e->plugin->check_position) {
4682 /* common part - we have plugin with position checking function, use it first */
4683 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4684 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004685 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004686 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004687 }
4688 }
4689
PavolVican22e88682017-02-14 22:38:18 +01004690 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004691 (*ext)->def = e;
4692 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004693 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004694 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
PavolVican22e88682017-02-14 22:38:18 +01004695
PavolVicanb0d84102017-02-15 16:32:42 +01004696 if (e->argument && !(*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004697 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
PavolVicanb0d84102017-02-15 16:32:42 +01004698 goto error;
4699 }
4700
PavolVican92f23622017-12-12 13:35:56 +01004701 if ((*ext)->flags & LYEXT_OPT_VALID &&
4702 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004703 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
PavolVican92f23622017-12-12 13:35:56 +01004704 }
4705
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004706 (*ext)->module = info->mod;
4707 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004708
PavolVican22e88682017-02-14 22:38:18 +01004709 /* extension type-specific part */
4710 if (e->plugin) {
4711 etype = e->plugin->type;
4712 } else {
4713 /* default type */
4714 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004715 }
PavolVican22e88682017-02-14 22:38:18 +01004716 switch (etype) {
4717 case LYEXT_FLAG:
4718 /* nothing change */
4719 break;
4720 case LYEXT_COMPLEX:
4721 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Michal Vasko53b7da02018-02-13 15:28:42 +01004722 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
PavolVican22e88682017-02-14 22:38:18 +01004723 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4724 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004725 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004726 if (info->data.yang) {
4727 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004728 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4729 (struct lys_ext_instance_complex*)(*ext))) {
4730 goto error;
4731 }
4732 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4733 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004734 goto error;
4735 }
PavolVicana3876672017-02-21 15:49:51 +01004736 }
4737 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4738 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004739 }
PavolVican22e88682017-02-14 22:38:18 +01004740 break;
4741 case LYEXT_ERR:
4742 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004743 LOGINT(ctx);
PavolVican22e88682017-02-14 22:38:18 +01004744 goto error;
4745 }
4746
PavolVican22e88682017-02-14 22:38:18 +01004747 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4748 goto error;
4749 }
4750 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004751 }
4752
4753 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004754error:
4755 free(ext_prefix);
4756 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004757}
4758
Michal Vasko730dfdf2015-08-11 14:48:05 +02004759/**
Pavol Vican855ca622016-09-05 13:07:54 +02004760 * @brief Resolve (find) choice default case. Does not log.
4761 *
4762 * @param[in] choic Choice to use.
4763 * @param[in] dflt Name of the default case.
4764 *
4765 * @return Pointer to the default node or NULL.
4766 */
4767static struct lys_node *
4768resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4769{
4770 struct lys_node *child, *ret;
4771
4772 LY_TREE_FOR(choic->child, child) {
4773 if (child->nodetype == LYS_USES) {
4774 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4775 if (ret) {
4776 return ret;
4777 }
4778 }
4779
4780 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004781 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004782 return child;
4783 }
4784 }
4785
4786 return NULL;
4787}
4788
4789/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004790 * @brief Resolve uses, apply augments, refines. Logs directly.
4791 *
Michal Vaskobb211122015-08-19 14:03:11 +02004792 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004793 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004794 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004795 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004796 */
Michal Vasko184521f2015-09-24 13:14:26 +02004797static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004798resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004799{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004800 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004801 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004802 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004803 struct lys_node_leaflist *llist;
4804 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004805 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004806 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004807 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004808 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004809 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004810 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004811
Michal Vasko71e1aa82015-08-12 12:17:51 +02004812 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004813
Radek Krejci93def382017-05-24 15:33:48 +02004814 /* check that the grouping is resolved (no unresolved uses inside) */
4815 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004816
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004817 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004818 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004819 if (node_aux->nodetype & LYS_GROUPING) {
4820 /* do not instantiate groupings from groupings */
4821 continue;
4822 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004823 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004824 if (!node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004825 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4826 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004827 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828 }
Pavol Vican55abd332016-07-12 15:54:49 +02004829 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004830 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 +02004831 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004832 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004833 }
4834 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004835 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004836
Michal Vaskodef0db12015-10-07 13:22:48 +02004837 /* we managed to copy the grouping, the rest must be possible to resolve */
4838
Pavol Vican855ca622016-09-05 13:07:54 +02004839 if (uses->refine_size) {
4840 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Michal Vasko53b7da02018-02-13 15:28:42 +01004841 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004842 }
4843
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004844 /* apply refines */
4845 for (i = 0; i < uses->refine_size; i++) {
4846 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004847 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4848 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004849 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004850 if (rc || !node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004851 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004852 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004853 }
4854
Radek Krejci1d82ef62015-08-07 14:44:40 +02004855 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004856 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4857 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004858 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004859 }
Pavol Vican855ca622016-09-05 13:07:54 +02004860 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004861
4862 /* description on any nodetype */
4863 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004864 lydict_remove(ctx, node->dsc);
4865 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004866 }
4867
4868 /* reference on any nodetype */
4869 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004870 lydict_remove(ctx, node->ref);
4871 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004872 }
4873
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004874 /* config on any nodetype,
4875 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4876 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004877 node->flags &= ~LYS_CONFIG_MASK;
4878 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004879 }
4880
4881 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004882 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004883 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004884 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004885 leaf = (struct lys_node_leaf *)node;
4886
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004887 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004888 lydict_remove(ctx, leaf->dflt);
4889 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4890
4891 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004892 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4893 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004894 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004895 }
Radek Krejci200bf712016-08-16 17:11:04 +02004896 } else if (node->nodetype == LYS_LEAFLIST) {
4897 /* leaf-list */
4898 llist = (struct lys_node_leaflist *)node;
4899
4900 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004901 for (j = 0; j < llist->dflt_size; j++) {
4902 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004903 }
4904 free(llist->dflt);
4905
4906 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02004907 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
Michal Vasko53b7da02018-02-13 15:28:42 +01004908 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004909 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004910 for (j = 0; j < llist->dflt_size; j++) {
4911 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004912 }
4913
4914 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004915 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004916 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004917 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004918 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004919 }
4920 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004921 }
4922 }
4923
4924 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004925 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004926 /* remove current value */
4927 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004928
Radek Krejcibf285832017-01-26 16:05:41 +01004929 /* set new value */
4930 node->flags |= (rfn->flags & LYS_MAND_MASK);
4931
Pavol Vican855ca622016-09-05 13:07:54 +02004932 if (rfn->flags & LYS_MAND_TRUE) {
4933 /* check if node has default value */
4934 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004935 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02004936 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004937 goto fail;
4938 }
4939 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004940 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02004941 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004942 goto fail;
4943 }
4944 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004945 }
4946
4947 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004948 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4949 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4950 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004951 }
4952
4953 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004954 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004955 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004956 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004957 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004958 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004959 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004960 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004961 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004962 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004963 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004964 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004965 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004966 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004967 }
4968 }
4969
4970 /* must in leaf, leaf-list, list, container or anyxml */
4971 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004972 switch (node->nodetype) {
4973 case LYS_LEAF:
4974 old_size = &((struct lys_node_leaf *)node)->must_size;
4975 old_must = &((struct lys_node_leaf *)node)->must;
4976 break;
4977 case LYS_LEAFLIST:
4978 old_size = &((struct lys_node_leaflist *)node)->must_size;
4979 old_must = &((struct lys_node_leaflist *)node)->must;
4980 break;
4981 case LYS_LIST:
4982 old_size = &((struct lys_node_list *)node)->must_size;
4983 old_must = &((struct lys_node_list *)node)->must;
4984 break;
4985 case LYS_CONTAINER:
4986 old_size = &((struct lys_node_container *)node)->must_size;
4987 old_must = &((struct lys_node_container *)node)->must;
4988 break;
4989 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004990 case LYS_ANYDATA:
4991 old_size = &((struct lys_node_anydata *)node)->must_size;
4992 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004993 break;
4994 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01004995 LOGINT(ctx);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004996 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004997 }
4998
4999 size = *old_size + rfn->must_size;
5000 must = realloc(*old_must, size * sizeof *rfn->must);
Michal Vasko53b7da02018-02-13 15:28:42 +01005001 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005002 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01005003 must[j].ext_size = rfn->must[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005004 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 +02005005 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02005006 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5007 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5008 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5009 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5010 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02005011 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005012 }
5013
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005014 *old_must = must;
5015 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02005016
5017 /* check XPath dependencies again */
5018 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5019 goto fail;
5020 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005021 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02005022
5023 /* if-feature in leaf, leaf-list, list, container or anyxml */
5024 if (rfn->iffeature_size) {
5025 old_size = &node->iffeature_size;
5026 old_iff = &node->iffeature;
5027
5028 size = *old_size + rfn->iffeature_size;
5029 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Michal Vasko53b7da02018-02-13 15:28:42 +01005030 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02005031 *old_iff = iff;
5032
Pavol Vican855ca622016-09-05 13:07:54 +02005033 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5034 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005035 if (usize1) {
5036 /* there is something to duplicate */
5037 /* duplicate compiled expression */
5038 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
5039 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Michal Vasko53b7da02018-02-13 15:28:42 +01005040 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005041 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005042
5043 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005044 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Michal Vasko53b7da02018-02-13 15:28:42 +01005045 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005046 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005047
Radek Krejci3a3b2002017-09-13 16:39:02 +02005048 /* duplicate extensions */
5049 iff[j].ext_size = rfn->iffeature[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005050 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
Radek Krejci3a3b2002017-09-13 16:39:02 +02005051 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5052 }
5053 (*old_size)++;
5054 }
5055 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005056 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005057 }
5058
5059 /* apply augments */
5060 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko97234262018-02-01 09:53:01 +01005061 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005062 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005063 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005064 }
5065 }
5066
Pavol Vican855ca622016-09-05 13:07:54 +02005067 /* check refines */
5068 for (i = 0; i < uses->refine_size; i++) {
5069 node = refine_nodes[i];
5070 rfn = &uses->refine[i];
5071
5072 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005073 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005074 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005075 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005076 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5077 (rfn->flags & LYS_CONFIG_W)) {
5078 /* setting config true under config false is prohibited */
Michal Vasko53b7da02018-02-13 15:28:42 +01005079 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5080 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005081 "changing config from 'false' to 'true' is prohibited while "
5082 "the target's parent is still config 'false'.");
5083 goto fail;
5084 }
5085
5086 /* inherit config change to the target children */
5087 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5088 if (rfn->flags & LYS_CONFIG_W) {
5089 if (iter->flags & LYS_CONFIG_SET) {
5090 /* config is set explicitely, go to next sibling */
5091 next = NULL;
5092 goto nextsibling;
5093 }
5094 } else { /* LYS_CONFIG_R */
5095 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5096 /* error - we would have config data under status data */
Michal Vasko53b7da02018-02-13 15:28:42 +01005097 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5098 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005099 "changing config from 'true' to 'false' is prohibited while the target "
5100 "has still a children with explicit config 'true'.");
5101 goto fail;
5102 }
5103 }
5104 /* change config */
5105 iter->flags &= ~LYS_CONFIG_MASK;
5106 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5107
5108 /* select next iter - modified LY_TREE_DFS_END */
5109 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5110 next = NULL;
5111 } else {
5112 next = iter->child;
5113 }
5114nextsibling:
5115 if (!next) {
5116 /* try siblings */
5117 next = iter->next;
5118 }
5119 while (!next) {
5120 /* parent is already processed, go to its sibling */
5121 iter = lys_parent(iter);
5122
5123 /* no siblings, go back through parents */
5124 if (iter == node) {
5125 /* we are done, no next element to process */
5126 break;
5127 }
5128 next = iter->next;
5129 }
5130 }
5131 }
5132
5133 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005134 if (rfn->dflt_size) {
5135 if (node->nodetype == LYS_CHOICE) {
5136 /* choice */
5137 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5138 rfn->dflt[0]);
5139 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005140 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005141 goto fail;
5142 }
5143 if (lyp_check_mandatory_choice(node)) {
5144 goto fail;
5145 }
Pavol Vican855ca622016-09-05 13:07:54 +02005146 }
5147 }
5148
5149 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005150 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005151 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005152 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5153 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005154 goto fail;
5155 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005156 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005157 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005158 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5159 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005160 goto fail;
5161 }
5162 }
5163
5164 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005165 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005166 if (node->nodetype == LYS_LEAFLIST) {
5167 llist = (struct lys_node_leaflist *)node;
5168 if (llist->dflt_size && llist->min) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005169 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5170 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005171 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5172 goto fail;
5173 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005174 } else if (node->nodetype == LYS_LEAF) {
5175 leaf = (struct lys_node_leaf *)node;
5176 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005177 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5178 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005179 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5180 goto fail;
5181 }
Pavol Vican855ca622016-09-05 13:07:54 +02005182 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005183
Pavol Vican855ca622016-09-05 13:07:54 +02005184 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005185 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005186 for (parent = node->parent;
5187 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5188 parent = parent->parent) {
5189 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5190 /* stop also on presence containers */
5191 break;
5192 }
5193 }
5194 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5195 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5196 if (lyp_check_mandatory_choice(parent)) {
5197 goto fail;
5198 }
5199 }
5200 }
5201 }
5202 free(refine_nodes);
5203
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005204 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005205
5206fail:
5207 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5208 lys_node_free(iter, NULL, 0);
5209 }
Pavol Vican855ca622016-09-05 13:07:54 +02005210 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005211 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212}
5213
Radek Krejci83a4bac2017-02-07 15:53:04 +01005214void
5215resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005216{
5217 int i;
5218
5219 assert(der && base);
5220
Radek Krejci018f1f52016-08-03 16:01:20 +02005221 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005222 /* create a set for backlinks if it does not exist */
5223 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005224 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005225 /* store backlink */
5226 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005227
Radek Krejci85a54be2016-10-20 12:39:56 +02005228 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005229 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005230 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005231 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005232}
5233
Michal Vasko730dfdf2015-08-11 14:48:05 +02005234/**
5235 * @brief Resolve base identity recursively. Does not log.
5236 *
5237 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005238 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005239 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005240 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005241 *
Radek Krejci219fa612016-08-15 10:36:51 +02005242 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005243 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005244static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005245resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005246 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005247{
Michal Vaskof02e3742015-08-05 16:27:02 +02005248 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005249 struct lys_ident *base = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005250 struct ly_ctx *ctx = module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005251
Radek Krejcicf509982015-12-15 09:22:44 +01005252 assert(ret);
5253
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005254 /* search module */
5255 for (i = 0; i < module->ident_size; i++) {
5256 if (!strcmp(basename, module->ident[i].name)) {
5257
5258 if (!ident) {
5259 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005260 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005261 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005262 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005263 }
5264
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005265 base = &module->ident[i];
5266 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005267 }
5268 }
5269
5270 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005271 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5272 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5273 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005274
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005275 if (!ident) {
5276 *ret = &module->inc[j].submodule->ident[i];
5277 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005278 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005279
5280 base = &module->inc[j].submodule->ident[i];
5281 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005282 }
5283 }
5284 }
5285
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005286matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005287 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005288 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005289 /* is it already completely resolved? */
5290 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005291 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005292 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5293
5294 /* simple check for circular reference,
5295 * the complete check is done as a side effect of using only completely
5296 * resolved identities (previous check of unres content) */
5297 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005298 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5299 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005300 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005301 }
5302
Radek Krejci06f64ed2016-08-15 11:07:44 +02005303 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005304 }
5305 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005306
Radek Krejcibabbff82016-02-19 13:31:37 +01005307 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005308 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005309 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005310 }
5311
Radek Krejci219fa612016-08-15 10:36:51 +02005312 /* base not found (maybe a forward reference) */
5313 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005314}
5315
Michal Vasko730dfdf2015-08-11 14:48:05 +02005316/**
5317 * @brief Resolve base identity. Logs directly.
5318 *
5319 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005320 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005321 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005322 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005323 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005324 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005325 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005326 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005327static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005328resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005329 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005330{
5331 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005332 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005333 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005334 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005335 struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005336 struct ly_ctx *ctx = module->ctx;
Radek Krejcicf509982015-12-15 09:22:44 +01005337
5338 assert((ident && !type) || (!ident && type));
5339
5340 if (!type) {
5341 /* have ident to resolve */
5342 ret = &target;
5343 flags = ident->flags;
5344 mod = ident->module;
5345 } else {
5346 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005347 ++type->info.ident.count;
5348 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 +01005349 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005350
5351 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005352 flags = type->parent->flags;
5353 mod = type->parent->module;
5354 }
Michal Vaskof2006002016-04-21 16:28:15 +02005355 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005356
5357 /* search for the base identity */
5358 name = strchr(basename, ':');
5359 if (name) {
5360 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005361 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005362 name++;
5363
Michal Vasko2d851a92015-10-20 16:16:36 +02005364 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005365 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005366 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005367 }
5368 } else {
5369 name = basename;
5370 }
5371
Radek Krejcic071c542016-01-27 14:57:51 +01005372 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005373 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
Radek Krejcic071c542016-01-27 14:57:51 +01005374 if (!module) {
5375 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01005376 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005377 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005378 }
5379
Radek Krejcic071c542016-01-27 14:57:51 +01005380 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005381 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5382 if (!rc) {
5383 assert(*ret);
5384
5385 /* check status */
5386 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5387 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5388 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005389 } else if (ident) {
5390 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005391 if (lys_main_module(mod)->implemented) {
5392 /* in case of the implemented identity, maintain backlinks to it
5393 * from the base identities to make it available when resolving
5394 * data with the identity values (not implemented identity is not
5395 * allowed as an identityref value). */
5396 resolve_identity_backlink_update(ident, *ret);
5397 }
Radek Krejci219fa612016-08-15 10:36:51 +02005398 }
5399 } else if (rc == EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005400 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005401 if (type) {
5402 --type->info.ident.count;
5403 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005404 }
5405
Radek Krejci219fa612016-08-15 10:36:51 +02005406 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005407}
5408
Radek Krejci9e6af732017-04-27 14:40:25 +02005409/*
5410 * 1 - true (der is derived from base)
5411 * 0 - false (der is not derived from base)
5412 */
5413static int
5414search_base_identity(struct lys_ident *der, struct lys_ident *base)
5415{
5416 int i;
5417
5418 if (der == base) {
5419 return 1;
5420 } else {
5421 for(i = 0; i < der->base_size; i++) {
5422 if (search_base_identity(der->base[i], base) == 1) {
5423 return 1;
5424 }
5425 }
5426 }
5427
5428 return 0;
5429}
5430
Michal Vasko730dfdf2015-08-11 14:48:05 +02005431/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005432 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005433 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005434 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005435 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005436 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005437 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005438 *
5439 * @return Pointer to the identity resolvent, NULL on error.
5440 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005441struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005442resolve_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 +02005443{
Radek Krejci9e6af732017-04-27 14:40:25 +02005444 const char *mod_name, *name;
Michal Vasko08767f72017-10-06 14:38:08 +02005445 char *str;
Radek Krejcidce5f972017-09-12 15:47:49 +02005446 int mod_name_len, nam_len, rc;
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005447 int need_implemented = 0;
Michal Vasko08767f72017-10-06 14:38:08 +02005448 unsigned int i, j;
Michal Vaskof2d43962016-09-02 11:10:16 +02005449 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005450 struct lys_module *imod = NULL, *m;
Michal Vasko53b7da02018-02-13 15:28:42 +01005451 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005452
Radek Krejci9e6af732017-04-27 14:40:25 +02005453 assert(type && ident_name && node && mod);
Michal Vasko53b7da02018-02-13 15:28:42 +01005454 ctx = mod->ctx;
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005455
Michal Vaskof2d43962016-09-02 11:10:16 +02005456 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005457 return NULL;
5458 }
5459
Michal Vasko50576712017-07-28 12:28:33 +02005460 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005461 if (rc < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005462 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005463 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005464 } else if (rc < (signed)strlen(ident_name)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005465 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005466 return NULL;
5467 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005468
5469 m = lys_main_module(mod); /* shortcut */
5470 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5471 /* identity is defined in the same module as node */
5472 imod = m;
5473 } else if (dflt) {
5474 /* solving identityref in default definition in schema -
5475 * find the identity's module in the imported modules list to have a correct revision */
5476 for (i = 0; i < mod->imp_size; i++) {
5477 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5478 imod = mod->imp[i].module;
5479 break;
5480 }
5481 }
5482 } else {
Michal Vasko08767f72017-10-06 14:38:08 +02005483 /* solving identityref in data - get the module from the context */
5484 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5485 imod = mod->ctx->models.list[i];
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005486 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
Radek Krejci9e6af732017-04-27 14:40:25 +02005487 break;
5488 }
Michal Vasko08767f72017-10-06 14:38:08 +02005489 imod = NULL;
5490 }
Radek Krejci5ba05102017-10-26 15:02:52 +02005491 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5492 /* we are currently parsing some module and checking XPath or a default value,
5493 * so take this module into account */
5494 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5495 imod = mod->ctx->models.parsing_sub_modules[i];
5496 if (imod->type) {
5497 /* skip submodules */
5498 continue;
5499 }
5500 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5501 break;
5502 }
5503 imod = NULL;
5504 }
5505 }
Michal Vasko08767f72017-10-06 14:38:08 +02005506 }
5507
Michal Vasko53b7da02018-02-13 15:28:42 +01005508 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
Michal Vasko08767f72017-10-06 14:38:08 +02005509 /* the needed module was not found, but it may have been expected so call the data callback */
5510 if (imod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005511 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci58523dc2017-10-27 10:00:17 +02005512 } else if (mod_name) {
Michal Vasko08767f72017-10-06 14:38:08 +02005513 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01005514 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
Michal Vasko08767f72017-10-06 14:38:08 +02005515 free(str);
Radek Krejci9e6af732017-04-27 14:40:25 +02005516 }
5517 }
5518 if (!imod) {
5519 goto fail;
5520 }
5521
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005522 if (m != imod || lys_main_module(type->parent->module) != mod) {
Michal Vasko08767f72017-10-06 14:38:08 +02005523 /* the type is not referencing the same schema,
Radek Krejci9e6af732017-04-27 14:40:25 +02005524 * THEN, we may need to make the module with the identity implemented, but only if it really
5525 * contains the identity */
5526 if (!imod->implemented) {
5527 cur = NULL;
5528 /* get the identity in the module */
5529 for (i = 0; i < imod->ident_size; i++) {
5530 if (!strcmp(name, imod->ident[i].name)) {
5531 cur = &imod->ident[i];
5532 break;
5533 }
5534 }
5535 if (!cur) {
5536 /* go through includes */
5537 for (j = 0; j < imod->inc_size; j++) {
5538 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5539 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5540 cur = &imod->inc[j].submodule->ident[i];
5541 break;
5542 }
5543 }
5544 }
5545 if (!cur) {
5546 goto fail;
5547 }
5548 }
5549
5550 /* check that identity is derived from one of the type's base */
5551 while (type->der) {
5552 for (i = 0; i < type->info.ident.count; i++) {
5553 if (search_base_identity(cur, type->info.ident.ref[i])) {
5554 /* cur's base matches the type's base */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005555 need_implemented = 1;
Radek Krejci9e6af732017-04-27 14:40:25 +02005556 goto match;
5557 }
5558 }
5559 type = &type->der->type;
5560 }
5561 /* matching base not found */
Michal Vasko53b7da02018-02-13 15:28:42 +01005562 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Radek Krejci9e6af732017-04-27 14:40:25 +02005563 goto fail;
5564 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005565 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005566
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005567 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005568 while (type->der) {
5569 for (i = 0; i < type->info.ident.count; ++i) {
5570 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005571
Radek Krejci85a54be2016-10-20 12:39:56 +02005572 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005573 /* there are some derived identities */
Michal Vasko08767f72017-10-06 14:38:08 +02005574 for (j = 0; j < cur->der->number; j++) {
5575 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005576 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005577 /* we have match */
5578 cur = der;
5579 goto match;
5580 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005581 }
5582 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005583 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005584 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005585 }
5586
Radek Krejci9e6af732017-04-27 14:40:25 +02005587fail:
Michal Vasko53b7da02018-02-13 15:28:42 +01005588 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005589 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005590
5591match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005592 for (i = 0; i < cur->iffeature_size; i++) {
5593 if (!resolve_iffeature(&cur->iffeature[i])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005594 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5595 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 +02005596 return NULL;
5597 }
5598 }
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005599 if (need_implemented) {
5600 if (dflt) {
5601 /* try to make the module implemented */
5602 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5603 imod->name, cur->name, mod->name);
5604 if (lys_set_implemented(imod)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005605 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005606 imod->name, cur->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01005607 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005608 goto fail;
5609 }
5610 } else {
5611 /* just say that it was found, but in a non-implemented module */
Michal Vasko53b7da02018-02-13 15:28:42 +01005612 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005613 lys_main_module(cur->module)->name);
Radek Krejci9e6af732017-04-27 14:40:25 +02005614 goto fail;
5615 }
5616 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005617 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005618}
5619
Michal Vasko730dfdf2015-08-11 14:48:05 +02005620/**
Michal Vaskobb211122015-08-19 14:03:11 +02005621 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005622 *
Michal Vaskobb211122015-08-19 14:03:11 +02005623 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005624 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005625 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005626 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005627 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005628static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005629resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005630{
Radek Krejci93def382017-05-24 15:33:48 +02005631 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005632 struct lys_node *par_grp;
Michal Vasko53b7da02018-02-13 15:28:42 +01005633 struct ly_ctx *ctx = uses->module->ctx;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005634
Radek Krejci6ff885d2017-01-03 14:06:22 +01005635 /* 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 +02005636 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5637 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5638 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005639 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 +02005640
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005641 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005642 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5643 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005644 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005645 return -1;
5646 } else if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005647 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005648 return -1;
5649 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005650 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005651 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005652 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005653 return -1;
5654 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005655 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005656 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005657 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005658 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005659 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005660 }
5661
Radek Krejci93def382017-05-24 15:33:48 +02005662 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005663 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005664 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005665 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005666 return -1;
5667 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005668 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005669 } else {
5670 /* instantiate grouping only when it is completely resolved */
5671 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005672 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005673 return EXIT_FAILURE;
5674 }
5675
Radek Krejci48464ed2016-03-17 15:44:09 +01005676 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005677 if (!rc) {
5678 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005679 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005680 assert(((struct lys_node_grp *)par_grp)->unres_count);
5681 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005682 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005683 }
Radek Krejcicf509982015-12-15 09:22:44 +01005684
5685 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005686 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005687 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005688 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005689 return -1;
5690 }
5691
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005692 return EXIT_SUCCESS;
5693 }
5694
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005695 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005696}
5697
Michal Vasko730dfdf2015-08-11 14:48:05 +02005698/**
Michal Vasko9957e592015-08-17 15:04:09 +02005699 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005700 *
Michal Vaskobb211122015-08-19 14:03:11 +02005701 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005702 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005703 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005704 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005705 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005706static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005707resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005708{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005709 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005710 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005711 char *s = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005712 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005713
5714 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005715 assert(keys_str);
5716
Radek Krejci5c08a992016-11-02 13:30:04 +01005717 if (!list->child) {
5718 /* no child, possible forward reference */
Michal Vasko53b7da02018-02-13 15:28:42 +01005719 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Radek Krejci5c08a992016-11-02 13:30:04 +01005720 return EXIT_FAILURE;
5721 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005722 /* get the key name */
5723 if ((value = strpbrk(keys_str, " \t\n"))) {
5724 len = value - keys_str;
5725 while (isspace(value[0])) {
5726 value++;
5727 }
5728 } else {
5729 len = strlen(keys_str);
5730 }
5731
Radek Krejcia98048c2017-05-24 16:35:48 +02005732 if (list->keys[i]) {
5733 /* skip already resolved keys */
5734 goto next;
5735 }
5736
Michal Vaskobb520442017-05-23 10:55:18 +02005737 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5738 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005739 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005740 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005741 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005742 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005743
Radek Krejci48464ed2016-03-17 15:44:09 +01005744 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005745 /* check_key logs */
5746 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005747 }
5748
Radek Krejcicf509982015-12-15 09:22:44 +01005749 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005750 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005751 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5752 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005753 return -1;
5754 }
5755
Radek Krejcia98048c2017-05-24 16:35:48 +02005756 /* default value - is ignored, keep it but print a warning */
5757 if (list->keys[i]->dflt) {
5758 /* log is not hidden only in case this resolving fails and in such a case
5759 * we cannot get here
5760 */
Michal Vasko53b7da02018-02-13 15:28:42 +01005761 assert(log_opt == ILO_STORE);
5762 log_opt = ILO_LOG;
5763 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
Michal Vasko395b0a02018-01-22 09:36:20 +01005764 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
Michal Vasko53b7da02018-02-13 15:28:42 +01005765 log_opt = ILO_STORE;
Radek Krejcia98048c2017-05-24 16:35:48 +02005766 free(s);
5767 }
5768
5769next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005770 /* prepare for next iteration */
5771 while (value && isspace(value[0])) {
5772 value++;
5773 }
5774 keys_str = value;
5775 }
5776
Michal Vaskof02e3742015-08-05 16:27:02 +02005777 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005778}
5779
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005780/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005781 * @brief Resolve (check) all must conditions of \p node.
5782 * Logs directly.
5783 *
5784 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005785 * @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 +02005786 *
5787 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5788 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005789static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005790resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005791{
Michal Vaskobf19d252015-10-08 15:39:17 +02005792 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005793 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005794 struct lys_restr *must;
5795 struct lyxp_set set;
Michal Vasko53b7da02018-02-13 15:28:42 +01005796 struct ly_ctx *ctx = node->schema->module->ctx;
Michal Vaskobf19d252015-10-08 15:39:17 +02005797
5798 assert(node);
5799 memset(&set, 0, sizeof set);
5800
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005801 if (inout_parent) {
5802 for (schema = lys_parent(node->schema);
5803 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5804 schema = lys_parent(schema));
5805 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005806 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005807 return -1;
5808 }
5809 must_size = ((struct lys_node_inout *)schema)->must_size;
5810 must = ((struct lys_node_inout *)schema)->must;
5811
5812 /* context node is the RPC/action */
5813 node = node->parent;
5814 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005815 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005816 return -1;
5817 }
5818 } else {
5819 switch (node->schema->nodetype) {
5820 case LYS_CONTAINER:
5821 must_size = ((struct lys_node_container *)node->schema)->must_size;
5822 must = ((struct lys_node_container *)node->schema)->must;
5823 break;
5824 case LYS_LEAF:
5825 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5826 must = ((struct lys_node_leaf *)node->schema)->must;
5827 break;
5828 case LYS_LEAFLIST:
5829 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5830 must = ((struct lys_node_leaflist *)node->schema)->must;
5831 break;
5832 case LYS_LIST:
5833 must_size = ((struct lys_node_list *)node->schema)->must_size;
5834 must = ((struct lys_node_list *)node->schema)->must;
5835 break;
5836 case LYS_ANYXML:
5837 case LYS_ANYDATA:
5838 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5839 must = ((struct lys_node_anydata *)node->schema)->must;
5840 break;
5841 case LYS_NOTIF:
5842 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5843 must = ((struct lys_node_notif *)node->schema)->must;
5844 break;
5845 default:
5846 must_size = 0;
5847 break;
5848 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005849 }
5850
5851 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005852 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005853 return -1;
5854 }
5855
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005856 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005857
Michal Vasko8146d4c2016-05-09 15:50:29 +02005858 if (!set.val.bool) {
Michal Vaskoc04173b2018-03-09 10:43:22 +01005859 if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005860 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5861 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01005862 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005863 if (must[i].emsg) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005864 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005865 }
5866 if (must[i].eapptag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005867 ly_err_last_set_apptag(ctx, must[i].eapptag);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005868 }
5869 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005870 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005871 }
5872 }
5873
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005874 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005875}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005876
Michal Vaskobf19d252015-10-08 15:39:17 +02005877/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005878 * @brief Resolve (find) when condition schema context node. Does not log.
5879 *
5880 * @param[in] schema Schema node with the when condition.
5881 * @param[out] ctx_snode When schema context node.
5882 * @param[out] ctx_snode_type Schema context node type.
5883 */
5884void
5885resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5886{
5887 const struct lys_node *sparent;
5888
5889 /* find a not schema-only node */
5890 *ctx_snode_type = LYXP_NODE_ELEM;
5891 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5892 if (schema->nodetype == LYS_AUGMENT) {
5893 sparent = ((struct lys_node_augment *)schema)->target;
5894 } else {
5895 sparent = schema->parent;
5896 }
5897 if (!sparent) {
5898 /* context node is the document root (fake root in our case) */
5899 if (schema->flags & LYS_CONFIG_W) {
5900 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5901 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005902 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005903 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005904 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskocb45f472018-02-12 10:47:42 +01005905 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
Michal Vasko508a50d2016-09-07 14:50:33 +02005906 break;
5907 }
5908 schema = sparent;
5909 }
5910
5911 *ctx_snode = (struct lys_node *)schema;
5912}
5913
5914/**
Michal Vaskocf024702015-10-08 15:01:42 +02005915 * @brief Resolve (find) when condition context node. Does not log.
5916 *
5917 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005918 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005919 * @param[out] ctx_node Context node.
5920 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005921 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005922 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005923 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005924static int
5925resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5926 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005927{
Michal Vaskocf024702015-10-08 15:01:42 +02005928 struct lyd_node *parent;
5929 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005930 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005931 uint16_t i, data_depth, schema_depth;
5932
Michal Vasko508a50d2016-09-07 14:50:33 +02005933 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005934
Michal Vaskofe989752016-09-08 08:47:26 +02005935 if (node_type == LYXP_NODE_ELEM) {
5936 /* standard element context node */
5937 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5938 for (sparent = schema, schema_depth = 0;
5939 sparent;
5940 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5941 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5942 ++schema_depth;
5943 }
Michal Vaskocf024702015-10-08 15:01:42 +02005944 }
Michal Vaskofe989752016-09-08 08:47:26 +02005945 if (data_depth < schema_depth) {
5946 return -1;
5947 }
Michal Vaskocf024702015-10-08 15:01:42 +02005948
Michal Vasko956e8542016-08-26 09:43:35 +02005949 /* find the corresponding data node */
5950 for (i = 0; i < data_depth - schema_depth; ++i) {
5951 node = node->parent;
5952 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005953 if (node->schema != schema) {
5954 return -1;
5955 }
Michal Vaskofe989752016-09-08 08:47:26 +02005956 } else {
5957 /* root context node */
5958 while (node->parent) {
5959 node = node->parent;
5960 }
5961 while (node->prev->next) {
5962 node = node->prev;
5963 }
Michal Vaskocf024702015-10-08 15:01:42 +02005964 }
5965
Michal Vaskoa59495d2016-08-22 09:18:58 +02005966 *ctx_node = node;
5967 *ctx_node_type = node_type;
5968 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005969}
5970
Michal Vasko76c3bd32016-08-24 16:02:52 +02005971/**
5972 * @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 +01005973 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005974 *
5975 * @param[in] snode Schema node, whose children instances need to be unlinked.
5976 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5977 * it is moved to point to another sibling still in the original tree.
5978 * @param[in,out] ctx_node When context node, adjusted if needed.
5979 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5980 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5981 * Ordering may change, but there will be no semantic change.
5982 *
5983 * @return EXIT_SUCCESS on success, -1 on error.
5984 */
5985static int
5986resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5987 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5988{
5989 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005990 const struct lys_node *slast;
Michal Vasko53b7da02018-02-13 15:28:42 +01005991 struct ly_ctx *ctx = snode->module->ctx;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005992
5993 switch (snode->nodetype) {
5994 case LYS_AUGMENT:
5995 case LYS_USES:
5996 case LYS_CHOICE:
5997 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005998 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005999 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006000 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6001 continue;
6002 }
6003
6004 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006005 return -1;
6006 }
6007 }
6008 break;
6009 case LYS_CONTAINER:
6010 case LYS_LIST:
6011 case LYS_LEAF:
6012 case LYS_LEAFLIST:
6013 case LYS_ANYXML:
6014 case LYS_ANYDATA:
6015 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6016 if (elem->schema == snode) {
6017
6018 if (elem == *ctx_node) {
6019 /* We are going to unlink our context node! This normally cannot happen,
6020 * but we use normal top-level data nodes for faking a document root node,
6021 * so if this is the context node, we just use the next top-level node.
6022 * Additionally, it can even happen that there are no top-level data nodes left,
6023 * all were unlinked, so in this case we pass NULL as the context node/data tree,
6024 * lyxp_eval() can handle this special situation.
6025 */
6026 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006027 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006028 return -1;
6029 }
6030
6031 if (elem->prev == elem) {
6032 /* unlinking last top-level element, use an empty data tree */
6033 *ctx_node = NULL;
6034 } else {
6035 /* in this case just use the previous/last top-level data node */
6036 *ctx_node = elem->prev;
6037 }
6038 } else if (elem == *node) {
6039 /* We are going to unlink the currently processed node. This does not matter that
6040 * much, but we would lose access to the original data tree, so just move our
6041 * pointer somewhere still inside it.
6042 */
6043 if ((*node)->prev != *node) {
6044 *node = (*node)->prev;
6045 } else {
6046 /* the processed node with sibings were all unlinked, oh well */
6047 *node = NULL;
6048 }
6049 }
6050
6051 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01006052 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006053 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006054 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006055 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006056 return -1;
6057 }
6058 } else {
6059 *unlinked_nodes = elem;
6060 }
6061
6062 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6063 /* there can be only one instance */
6064 break;
6065 }
6066 }
6067 }
6068 break;
6069 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006070 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006071 return -1;
6072 }
6073
6074 return EXIT_SUCCESS;
6075}
6076
6077/**
6078 * @brief Relink the unlinked nodes back.
6079 *
6080 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6081 * we simply need a sibling from the original data tree.
6082 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6083 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6084 * or the sibling of \p unlinked_nodes.
6085 *
6086 * @return EXIT_SUCCESS on success, -1 on error.
6087 */
6088static int
6089resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6090{
6091 struct lyd_node *elem;
6092
6093 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006094 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006095 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006096 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006097 return -1;
6098 }
6099 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006100 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006101 return -1;
6102 }
6103 }
6104 }
6105
6106 return EXIT_SUCCESS;
6107}
6108
Radek Krejci03b71f72016-03-16 11:10:09 +01006109int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006110resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01006111{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006112 int ret = 0;
6113 uint8_t must_size;
6114 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02006115
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006116 assert(node);
6117
6118 schema = node->schema;
6119
6120 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02006121 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01006122 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006123 must_size = ((struct lys_node_container *)schema)->must_size;
6124 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006125 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006126 must_size = ((struct lys_node_leaf *)schema)->must_size;
6127 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006128 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006129 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6130 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006131 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006132 must_size = ((struct lys_node_list *)schema)->must_size;
6133 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006134 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02006135 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006136 must_size = ((struct lys_node_anydata *)schema)->must_size;
6137 break;
6138 case LYS_NOTIF:
6139 must_size = ((struct lys_node_notif *)schema)->must_size;
6140 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006141 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006142 must_size = 0;
6143 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006144 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006145
6146 if (must_size) {
6147 ++ret;
6148 }
6149
6150 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6151 if (!node->prev->next) {
6152 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6153 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6154 ret += 0x2;
6155 }
6156 }
6157
6158 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006159}
6160
6161int
Radek Krejci46165822016-08-26 14:06:27 +02006162resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006163{
Radek Krejci46165822016-08-26 14:06:27 +02006164 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006165
Radek Krejci46165822016-08-26 14:06:27 +02006166 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006167
Radek Krejci46165822016-08-26 14:06:27 +02006168 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006169 return 1;
6170 }
6171
Radek Krejci46165822016-08-26 14:06:27 +02006172 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006173 goto check_augment;
6174
Radek Krejci46165822016-08-26 14:06:27 +02006175 while (parent) {
6176 /* stop conditions */
6177 if (!mode) {
6178 /* stop on node that can be instantiated in data tree */
6179 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6180 break;
6181 }
6182 } else {
6183 /* stop on the specified node */
6184 if (parent == stop) {
6185 break;
6186 }
6187 }
6188
6189 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006190 return 1;
6191 }
6192check_augment:
6193
6194 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006195 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006196 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006197 }
6198 parent = lys_parent(parent);
6199 }
6200
6201 return 0;
6202}
6203
Michal Vaskocf024702015-10-08 15:01:42 +02006204/**
6205 * @brief Resolve (check) all when conditions relevant for \p node.
6206 * Logs directly.
6207 *
6208 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02006209 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6210 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02006211 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006212 * @return
6213 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02006214 * 0 - all "when" statements true
6215 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01006216 * 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 +02006217 */
Radek Krejci46165822016-08-26 14:06:27 +02006218int
Michal Vasko0b963112017-08-11 12:45:36 +02006219resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02006220{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006221 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006222 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006223 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006224 enum lyxp_node_type ctx_node_type;
Michal Vasko53b7da02018-02-13 15:28:42 +01006225 struct ly_ctx *ctx = node->schema->module->ctx;
Radek Krejci51093642016-03-29 10:14:59 +02006226 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006227
6228 assert(node);
6229 memset(&set, 0, sizeof set);
6230
Michal Vasko78d97e22017-02-21 09:54:38 +01006231 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006232 /* make the node dummy for the evaluation */
6233 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006234 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6235 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006236 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006237 if (rc) {
6238 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006239 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006240 }
Radek Krejci51093642016-03-29 10:14:59 +02006241 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006242 }
6243
Radek Krejci03b71f72016-03-16 11:10:09 +01006244 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006245 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006246 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006247 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006248 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006249 || ((((struct lys_node_container *)node->schema)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6250 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006251 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6252 ((struct lys_node_container *)node->schema)->when->cond);
6253 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006254 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006255 if (failed_when) {
6256 *failed_when = ((struct lys_node_container *)node->schema)->when;
6257 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006258 goto cleanup;
6259 }
Michal Vaskocf024702015-10-08 15:01:42 +02006260 }
Radek Krejci51093642016-03-29 10:14:59 +02006261
6262 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006263 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006264 }
6265
Michal Vasko90fc2a32016-08-24 15:58:58 +02006266 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006267 goto check_augment;
6268
6269 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006270 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6271 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006272 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006273 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006274 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006275 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006276 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006277 }
6278 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006279
6280 unlinked_nodes = NULL;
6281 /* we do not want our node pointer to change */
6282 tmp_node = node;
6283 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6284 if (rc) {
6285 goto cleanup;
6286 }
6287
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006288 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6289 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006290
6291 if (unlinked_nodes && ctx_node) {
6292 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6293 rc = -1;
6294 goto cleanup;
6295 }
6296 }
6297
Radek Krejci03b71f72016-03-16 11:10:09 +01006298 if (rc) {
6299 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006300 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006301 }
Radek Krejci51093642016-03-29 10:14:59 +02006302 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006303 }
6304
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006305 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006306 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02006307 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006308 || ((((struct lys_node_uses *)sparent)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6309 || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006310 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6311 ((struct lys_node_uses *)sparent)->when->cond);
6312 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006313 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko53b7da02018-02-13 15:28:42 +01006314 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006315 if (failed_when) {
6316 *failed_when = ((struct lys_node_uses *)sparent)->when;
6317 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006318 goto cleanup;
6319 }
Michal Vaskocf024702015-10-08 15:01:42 +02006320 }
Radek Krejci51093642016-03-29 10:14:59 +02006321
6322 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006323 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006324 }
6325
6326check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006327 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006328 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006329 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006330 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006331 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006332 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006333 }
6334 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006335
6336 unlinked_nodes = NULL;
6337 tmp_node = node;
6338 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6339 if (rc) {
6340 goto cleanup;
6341 }
6342
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006343 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6344 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006345
6346 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6347 * so the tree did not actually change and there is nothing for us to do
6348 */
6349 if (unlinked_nodes && ctx_node) {
6350 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6351 rc = -1;
6352 goto cleanup;
6353 }
6354 }
6355
Radek Krejci03b71f72016-03-16 11:10:09 +01006356 if (rc) {
6357 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006358 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006359 }
Radek Krejci51093642016-03-29 10:14:59 +02006360 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006361 }
6362
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006363 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006364 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006365 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006366 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006367 || ((((struct lys_node_augment *)sparent->parent)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6368 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006369 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006370 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006371 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006372 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006373 if (failed_when) {
6374 *failed_when = ((struct lys_node_augment *)sparent->parent)->when;
6375 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006376 goto cleanup;
6377 }
Michal Vaskocf024702015-10-08 15:01:42 +02006378 }
Radek Krejci51093642016-03-29 10:14:59 +02006379
6380 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006381 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006382 }
6383
Michal Vasko90fc2a32016-08-24 15:58:58 +02006384 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006385 }
6386
Radek Krejci0b7704f2016-03-18 12:16:14 +01006387 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006388
Radek Krejci51093642016-03-29 10:14:59 +02006389cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006390 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006391 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006392 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006393}
6394
Radek Krejcicbb473e2016-09-16 14:48:32 +02006395static int
6396check_leafref_features(struct lys_type *type)
6397{
6398 struct lys_node *iter;
6399 struct ly_set *src_parents, *trg_parents, *features;
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006400 struct lys_node_augment *aug;
Michal Vasko53b7da02018-02-13 15:28:42 +01006401 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006402 unsigned int i, j, size, x;
6403 int ret = EXIT_SUCCESS;
6404
6405 assert(type->parent);
6406
6407 src_parents = ly_set_new();
6408 trg_parents = ly_set_new();
6409 features = ly_set_new();
6410
6411 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006412 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006413 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6414 continue;
6415 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006416 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006417 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006418 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006419 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006420 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006421 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006422 ret = EXIT_FAILURE;
6423 goto cleanup;
6424 }
6425 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006426 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6427 }
6428 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006429 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006430 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6431 continue;
6432 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006433 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006434 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006435 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006436 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006437 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006438 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006439 ret = EXIT_FAILURE;
6440 goto cleanup;
6441 }
6442 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006443 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6444 }
6445
6446 /* compare the features used in if-feature statements in the rest of both
6447 * chains of parents. The set of features used for target must be a subset
6448 * of features used for the leafref. This is not a perfect, we should compare
6449 * the truth tables but it could require too much resources, so we simplify that */
6450 for (i = 0; i < src_parents->number; i++) {
6451 iter = src_parents->set.s[i]; /* shortcut */
6452 if (!iter->iffeature_size) {
6453 continue;
6454 }
6455 for (j = 0; j < iter->iffeature_size; j++) {
6456 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6457 for (; size; size--) {
6458 if (!iter->iffeature[j].features[size - 1]) {
6459 /* not yet resolved feature, postpone this check */
6460 ret = EXIT_FAILURE;
6461 goto cleanup;
6462 }
6463 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6464 }
6465 }
6466 }
6467 x = features->number;
6468 for (i = 0; i < trg_parents->number; i++) {
6469 iter = trg_parents->set.s[i]; /* shortcut */
6470 if (!iter->iffeature_size) {
6471 continue;
6472 }
6473 for (j = 0; j < iter->iffeature_size; j++) {
6474 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6475 for (; size; size--) {
6476 if (!iter->iffeature[j].features[size - 1]) {
6477 /* not yet resolved feature, postpone this check */
6478 ret = EXIT_FAILURE;
6479 goto cleanup;
6480 }
Michal Vasko53b7da02018-02-13 15:28:42 +01006481 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006482 /* the feature is not present in features set of target's parents chain */
Michal Vasko53b7da02018-02-13 15:28:42 +01006483 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
6484 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006485 "Leafref is not conditional based on \"%s\" feature as its target.",
6486 iter->iffeature[j].features[size - 1]->name);
6487 ret = -1;
6488 goto cleanup;
6489 }
6490 }
6491 }
6492 }
6493
6494cleanup:
6495 ly_set_free(features);
6496 ly_set_free(src_parents);
6497 ly_set_free(trg_parents);
6498
6499 return ret;
6500}
6501
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006502static int
6503check_type_union_leafref(struct lys_type *type)
6504{
6505 uint8_t i;
6506
6507 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6508 /* go through unions and look for leafref */
6509 for (i = 0; i < type->info.uni.count; ++i) {
6510 switch (type->info.uni.types[i].base) {
6511 case LY_TYPE_LEAFREF:
6512 return 1;
6513 case LY_TYPE_UNION:
6514 if (check_type_union_leafref(&type->info.uni.types[i])) {
6515 return 1;
6516 }
6517 break;
6518 default:
6519 break;
6520 }
6521 }
6522
6523 return 0;
6524 }
6525
6526 /* just inherit the flag value */
6527 return type->der->has_union_leafref;
6528}
6529
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006530/**
Michal Vaskobb211122015-08-19 14:03:11 +02006531 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006532 *
6533 * @param[in] mod Main module.
6534 * @param[in] item Item to resolve. Type determined by \p type.
6535 * @param[in] type Type of the unresolved item.
6536 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006537 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006538 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006539 *
6540 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6541 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006542static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006543resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006544 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006545{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006546 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Michal Vasko53b7da02018-02-13 15:28:42 +01006547 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006548 unsigned int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01006549 struct ly_ctx * ctx = mod->ctx;
Radek Krejci80056d52017-01-05 13:13:33 +01006550 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006551 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006552 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006553
Radek Krejcic79c6b12016-07-26 15:11:49 +02006554 struct ly_set *refs, *procs;
6555 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006556 struct lys_ident *ident;
6557 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006558 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006559 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006560 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006561 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006562 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006563 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006564 struct lys_ext_instance *ext, **extlist;
6565 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006566
6567 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006568 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006569 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006570 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006571 ident = item;
6572
Radek Krejci018f1f52016-08-03 16:01:20 +02006573 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006574 break;
6575 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006576 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006577 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006578 stype = item;
6579
Radek Krejci018f1f52016-08-03 16:01:20 +02006580 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006581 break;
6582 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006583 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006584 stype = item;
6585
Michal Vasko1c007172017-03-10 10:20:44 +01006586 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6587 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006588 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006589
Michal Vaskobb520442017-05-23 10:55:18 +02006590 if (lys_node_module(node)->implemented) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006591 /* make all the modules in the path implemented */
Michal Vaskobb520442017-05-23 10:55:18 +02006592 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6593 if (!lys_node_module(next)->implemented) {
6594 if (lys_set_implemented(lys_node_module(next))) {
6595 rc = -1;
6596 break;
6597 }
6598 }
6599 }
6600 if (next) {
6601 break;
6602 }
6603
6604 /* store the backlink from leafref target */
6605 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6606 rc = -1;
Michal Vaskobe136f62017-09-21 12:08:39 +02006607 break;
6608 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006609 }
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006610
6611 /* check if leafref and its target are under common if-features */
6612 rc = check_leafref_features(stype);
Radek Krejci46c4cd72016-01-21 15:13:52 +01006613 }
6614
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006615 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006616 case UNRES_TYPE_DER_EXT:
6617 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006618 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006619 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006620 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006621 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006622 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006623 /* parent */
6624 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006625 stype = item;
6626
Michal Vasko88c29542015-11-27 14:57:53 +01006627 /* HACK type->der is temporarily unparsed type statement */
6628 yin = (struct lyxml_elem *)stype->der;
6629 stype->der = NULL;
6630
Pavol Vicana0e4e672016-02-24 12:20:04 +01006631 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6632 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006633 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006634
6635 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006636 /* may try again later */
6637 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006638 } else {
6639 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006640 lydict_remove(ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006641 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006642 }
6643
Michal Vasko88c29542015-11-27 14:57:53 +01006644 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006645 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006646 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006647 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006648 lyxml_free(ctx, yin);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006649 } else {
6650 /* may try again later, put all back how it was */
6651 stype->der = (struct lys_tpdf *)yin;
6652 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006653 }
Radek Krejcic13db382016-08-16 10:52:42 +02006654 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006655 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006656 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006657 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
Radek Krejci2c2fce82016-08-01 13:52:26 +02006658 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006659
6660 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6661 /* fill typedef union leafref flag */
6662 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6663 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6664 /* copy the type in case it has union leafref flag */
6665 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006666 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006667 return -1;
6668 }
6669 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02006670 } else if (rc == EXIT_FAILURE && !(stype->flags & LYTYPE_GRP)) {
Radek Krejcic13db382016-08-16 10:52:42 +02006671 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6672 * 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 +02006673 * grouping. The grouping cannot be used unless the unres counter is 0.
Michal Vasko70bf8e52018-03-26 11:32:33 +02006674 * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006675 * of the type's base member. */
6676 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6677 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006678 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006679 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006680 return -1;
6681 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02006682 stype->flags |= LYTYPE_GRP;
Radek Krejcic13db382016-08-16 10:52:42 +02006683 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006684 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006685 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006686 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006687 iff_data = str_snode;
6688 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006689 if (!rc) {
6690 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006691 if (iff_data->infeature) {
6692 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6693 feat = *((struct lys_feature **)item);
6694 if (!feat->depfeatures) {
6695 feat->depfeatures = ly_set_new();
6696 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006697 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006698 }
6699 /* cleanup temporary data */
Michal Vasko53b7da02018-02-13 15:28:42 +01006700 lydict_remove(ctx, iff_data->fname);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006701 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006702 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006703 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006704 case UNRES_FEATURE:
6705 feat = (struct lys_feature *)item;
6706
6707 if (feat->iffeature_size) {
6708 refs = ly_set_new();
6709 procs = ly_set_new();
6710 ly_set_add(procs, feat, 0);
6711
6712 while (procs->number) {
6713 ref = procs->set.g[procs->number - 1];
6714 ly_set_rm_index(procs, procs->number - 1);
6715
6716 for (i = 0; i < ref->iffeature_size; i++) {
6717 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6718 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006719 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006720 if (ref->iffeature[i].features[j - 1] == feat) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006721 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006722 goto featurecheckdone;
6723 }
6724
6725 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6726 k = refs->number;
6727 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6728 /* not yet seen feature, add it for processing */
6729 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6730 }
6731 }
6732 } else {
6733 /* forward reference */
6734 rc = EXIT_FAILURE;
6735 goto featurecheckdone;
6736 }
6737 }
6738
6739 }
6740 }
6741 rc = EXIT_SUCCESS;
6742
6743featurecheckdone:
6744 ly_set_free(refs);
6745 ly_set_free(procs);
6746 }
6747
6748 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006749 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006750 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006751 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006752 case UNRES_TYPEDEF_DFLT:
6753 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006754 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006755 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006756 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006757 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006758 break;
6759 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006760 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006761 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006762 choic = item;
6763
Radek Krejcie00d2312016-08-12 15:27:49 +02006764 if (!choic->dflt) {
6765 choic->dflt = resolve_choice_dflt(choic, expr);
6766 }
Michal Vasko7955b362015-09-04 14:18:15 +02006767 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006768 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006769 } else {
6770 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006771 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006772 break;
6773 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006774 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006775 break;
6776 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006777 unique_info = (struct unres_list_uniq *)item;
6778 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006779 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006780 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006781 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006782 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006783 case UNRES_XPATH:
6784 node = (struct lys_node *)item;
Michal Vasko895c11f2018-03-12 11:35:58 +01006785 rc = check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006786 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006787 case UNRES_EXT:
6788 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006789 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006790 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006791 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006792 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006793 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006794 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006795 if (eplugin) {
6796 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006797 u = malloc(sizeof *u);
Michal Vasko53b7da02018-02-13 15:28:42 +01006798 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006799 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006800 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6801 /* something really bad happend since the extension finalization is not actually
6802 * being resolved while adding into unres, so something more serious with the unres
6803 * list itself must happened */
6804 return -1;
6805 }
Radek Krejci80056d52017-01-05 13:13:33 +01006806 }
6807 }
Radek Krejci79685c92017-02-17 10:49:43 +01006808 }
6809 if (!rc || rc == -1) {
6810 /* cleanup on success or fatal error */
6811 if (ext_data->datatype == LYS_IN_YIN) {
6812 /* YIN */
Michal Vasko53b7da02018-02-13 15:28:42 +01006813 lyxml_free(ctx, ext_data->data.yin);
Radek Krejci79685c92017-02-17 10:49:43 +01006814 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006815 /* YANG */
6816 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006817 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006818 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006819 }
6820 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006821 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006822 u = (uint8_t *)str_snode;
6823 ext = (*(struct lys_ext_instance ***)item)[*u];
6824 free(u);
6825
Radek Krejci80056d52017-01-05 13:13:33 +01006826 eplugin = ext->def->plugin;
6827
6828 /* inherit */
6829 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6830 root = (struct lys_node *)ext->parent;
6831 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6832 LY_TREE_DFS_BEGIN(root->child, next, node) {
6833 /* first, check if the node already contain instance of the same extension,
6834 * in such a case we won't inherit. In case the node was actually defined as
6835 * augment data, we are supposed to check the same way also the augment node itself */
6836 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6837 goto inherit_dfs_sibling;
6838 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6839 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6840 goto inherit_dfs_sibling;
6841 }
6842
6843 if (eplugin->check_inherit) {
6844 /* we have a callback to check the inheritance, use it */
6845 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6846 case 0:
6847 /* yes - continue with the inheriting code */
6848 break;
6849 case 1:
6850 /* no - continue with the node's sibling */
6851 goto inherit_dfs_sibling;
6852 case 2:
6853 /* no, but continue with the children, just skip the inheriting code for this node */
6854 goto inherit_dfs_child;
6855 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006856 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
Radek Krejci80056d52017-01-05 13:13:33 +01006857 ext->def->module->name, ext->def->name, rc);
6858 }
6859 }
6860
6861 /* inherit the extension */
6862 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Michal Vasko53b7da02018-02-13 15:28:42 +01006863 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006864 extlist[node->ext_size] = malloc(sizeof **extlist);
Michal Vasko53b7da02018-02-13 15:28:42 +01006865 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006866 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6867 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6868
6869 node->ext = extlist;
6870 node->ext_size++;
6871
6872inherit_dfs_child:
6873 /* modification of - select element for the next run - children first */
6874 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6875 next = NULL;
6876 } else {
6877 next = node->child;
6878 }
6879 if (!next) {
6880inherit_dfs_sibling:
6881 /* no children, try siblings */
6882 next = node->next;
6883 }
6884 while (!next) {
6885 /* go to the parent */
6886 node = lys_parent(node);
6887
6888 /* we are done if we are back in the root (the starter's parent */
6889 if (node == root) {
6890 break;
6891 }
6892
6893 /* parent is already processed, go to its sibling */
6894 next = node->next;
6895 }
6896 }
6897 }
6898 }
6899
6900 /* final check */
6901 if (eplugin->check_result) {
6902 if ((*eplugin->check_result)(ext)) {
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01006903 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
Radek Krejci80056d52017-01-05 13:13:33 +01006904 return -1;
6905 }
6906 }
6907
6908 rc = 0;
6909 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006910 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006911 LOGINT(ctx);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006912 break;
6913 }
6914
Radek Krejci54081ce2016-08-12 15:21:47 +02006915 if (has_str && !rc) {
6916 /* the string is no more needed in case of success.
6917 * In case of forward reference, we will try to resolve the string later */
Michal Vasko53b7da02018-02-13 15:28:42 +01006918 lydict_remove(ctx, str_snode);
Radek Krejci4f78b532016-02-17 13:43:00 +01006919 }
6920
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006921 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006922}
6923
Michal Vaskof02e3742015-08-05 16:27:02 +02006924/* logs directly */
6925static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006926print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006927{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006928 struct lyxml_elem *xml;
6929 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006930 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006931 const char *name = NULL;
6932 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006933
Michal Vaskof02e3742015-08-05 16:27:02 +02006934 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006935 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006936 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006937 break;
6938 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006939 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006940 break;
6941 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006942 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6943 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006944 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006945 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006946 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006947 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006948 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6949 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006950 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006951 } else {
6952 LY_TREE_FOR(xml->attr, attr) {
6953 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006954 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006955 break;
6956 }
6957 }
6958 assert(attr);
6959 }
Radek Krejcie534c132016-11-23 13:32:31 +01006960 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006961 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006962 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006963 iff_data = str_node;
6964 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006965 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006966 case UNRES_FEATURE:
6967 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6968 ((struct lys_feature *)item)->name);
6969 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006970 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006971 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006972 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006973 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006974 case UNRES_TYPE_DFLT:
Michal Vaskoba835cd2018-02-23 09:25:48 +01006975 if (*(char **)str_node) {
6976 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
Radek Krejci2e2de832016-10-13 16:12:26 +02006977 } /* else no default value in the type itself, but we are checking some restrictions against
6978 * possible default value of some base type. The failure is caused by not resolved base type,
6979 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006980 break;
6981 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006982 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006983 break;
6984 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006985 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006986 break;
6987 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006988 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006989 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006990 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006991 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6992 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006993 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006994 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006995 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6996 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006997 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006998 case UNRES_EXT:
6999 extinfo = (struct unres_ext *)str_node;
7000 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7001 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7002 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007003 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007004 LOGINT(NULL);
Michal Vaskof02e3742015-08-05 16:27:02 +02007005 break;
7006 }
7007}
7008
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007009/**
Michal Vaskobb211122015-08-19 14:03:11 +02007010 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007011 *
7012 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007013 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007014 *
Michal Vasko92b8a382015-08-19 14:03:49 +02007015 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007016 */
Michal Vaskof02e3742015-08-05 16:27:02 +02007017int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007018resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02007019{
Radek Krejci010e54b2016-03-15 09:40:34 +01007020 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko53b7da02018-02-13 15:28:42 +01007021 struct ly_err_item *prev_eitem;
7022 enum int_log_opts prev_ilo;
7023 LY_ERR prev_ly_errno;
7024 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007025
7026 assert(unres);
7027
Michal Vaskoe8734262016-09-29 14:12:06 +02007028 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01007029 prev_ly_errno = ly_errno;
7030 ly_ilo_change(mod->ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02007031
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007032 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02007033 do {
Michal Vasko88c29542015-11-27 14:57:53 +01007034 unres_count = 0;
7035 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02007036
7037 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02007038 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02007039 * if-features are resolved here to make sure that we will have all if-features for
7040 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02007041 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02007042 continue;
7043 }
Radek Krejci018f1f52016-08-03 16:01:20 +02007044 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01007045 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02007046
Michal Vasko88c29542015-11-27 14:57:53 +01007047 ++unres_count;
Michal Vaskof96dfb62017-08-17 12:23:49 +02007048 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 +02007049 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02007050 unres->type[i] = UNRES_RESOLVED;
7051 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01007052 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02007053 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007054 goto error;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007055 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007056 /* forward reference, erase errors */
7057 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02007058 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007059 }
Michal Vasko88c29542015-11-27 14:57:53 +01007060 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02007061
Michal Vasko88c29542015-11-27 14:57:53 +01007062 if (res_count < unres_count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007063 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7064 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02007065
7066 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02007067 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02007068 continue;
7069 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02007070 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 +02007071 }
Michal Vasko92b8a382015-08-19 14:03:49 +02007072 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007073 }
7074
Michal Vaskof96dfb62017-08-17 12:23:49 +02007075 /* the rest except finalizing extensions and xpath */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007076 for (i = 0; i < unres->count; ++i) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02007077 if ((unres->type[i] == UNRES_RESOLVED) || (unres->type[i] == UNRES_EXT_FINALIZE) || (unres->type[i] == UNRES_XPATH)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007078 continue;
7079 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02007080
Michal Vaskof96dfb62017-08-17 12:23:49 +02007081 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 +01007082 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02007083 if (unres->type[i] == UNRES_LIST_UNIQ) {
7084 /* free the allocated structure */
7085 free(unres->item[i]);
7086 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007087 unres->type[i] = UNRES_RESOLVED;
7088 ++resolved;
7089 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007090 goto error;
Radek Krejci791f6c72017-02-22 15:23:39 +01007091 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007092 /* forward reference, erase errors */
7093 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007094 }
7095 }
7096
Michal Vasko53b7da02018-02-13 15:28:42 +01007097 /* log normally now */
7098 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
7099 ly_errno = prev_ly_errno;
Radek Krejci010e54b2016-03-15 09:40:34 +01007100
Radek Krejci80056d52017-01-05 13:13:33 +01007101 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7102 for (i = 0; i < unres->count; ++i) {
7103 if (unres->type[i] != UNRES_EXT_FINALIZE) {
7104 continue;
7105 }
7106
Michal Vaskof96dfb62017-08-17 12:23:49 +02007107 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 +01007108 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01007109 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01007110 ++resolved;
7111 }
Radek Krejci791f6c72017-02-22 15:23:39 +01007112 /* else error - it was already printed, but resolved was not increased,
7113 so this unres item will not be resolved again in the following code,
7114 but it will cause returning -1 at the end, this way we are able to
7115 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01007116 }
7117
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007118 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007119 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
Michal Vaskof96dfb62017-08-17 12:23:49 +02007120 * all the validation errors, xpath is resolved only here to properly print all the messages
Radek Krejci010e54b2016-03-15 09:40:34 +01007121 */
7122 for (i = 0; i < unres->count; ++i) {
7123 if (unres->type[i] == UNRES_RESOLVED) {
7124 continue;
7125 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02007126 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 +01007127 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01007128 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01007129 unres->type[i] = UNRES_RESOLVED;
7130 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01007131 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007132 }
Radek Krejcib3142312016-11-09 11:04:12 +01007133 if (resolved < unres->count) {
7134 return -1;
7135 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007136 }
7137
Michal Vaskoe8734262016-09-29 14:12:06 +02007138 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01007139 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007140 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01007141
7142error:
7143 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 1);
7144 /* ly_errno will be set accordingly, we do not want to keep the previous value */
7145 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007146}
7147
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007148/**
Michal Vaskobb211122015-08-19 14:03:11 +02007149 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007150 *
7151 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007152 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007153 * @param[in] item Item to resolve. Type determined by \p type.
7154 * @param[in] type Type of the unresolved item.
7155 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007156 *
Michal Vasko3767fb22016-07-21 12:10:57 +02007157 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007158 */
7159int
Radek Krejci48464ed2016-03-17 15:44:09 +01007160unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7161 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007162{
Radek Krejci54081ce2016-08-12 15:21:47 +02007163 int rc;
7164 const char *dictstr;
7165
7166 dictstr = lydict_insert(mod->ctx, str, 0);
7167 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7168
Radek Krejcid9c0ce22017-01-20 15:20:16 +01007169 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02007170 lydict_remove(mod->ctx, dictstr);
7171 }
7172 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007173}
7174
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007175/**
Michal Vaskobb211122015-08-19 14:03:11 +02007176 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007177 *
7178 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007179 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007180 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01007181 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007182 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007183 *
Radek Krejci62f7aad2017-10-26 14:53:52 +02007184 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007185 */
7186int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007187unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01007188 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007189{
Michal Vasko53b7da02018-02-13 15:28:42 +01007190 int rc;
Radek Krejci62f7aad2017-10-26 14:53:52 +02007191 uint32_t u;
Michal Vasko53b7da02018-02-13 15:28:42 +01007192 enum int_log_opts prev_ilo;
7193 struct ly_err_item *prev_eitem;
7194 LY_ERR prev_ly_errno;
Michal Vasko88c29542015-11-27 14:57:53 +01007195 struct lyxml_elem *yin;
Michal Vasko53b7da02018-02-13 15:28:42 +01007196 struct ly_ctx *ctx = mod->ctx;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007197
Michal Vasko9bf425b2015-10-22 11:42:03 +02007198 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
7199 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007200
Radek Krejci850a5de2016-11-08 14:06:40 +01007201 /* check for duplicities in unres */
7202 for (u = 0; u < unres->count; u++) {
7203 if (unres->type[u] == type && unres->item[u] == item &&
7204 unres->str_snode[u] == snode && unres->module[u] == mod) {
Radek Krejci62f7aad2017-10-26 14:53:52 +02007205 /* duplication can happen when the node contains multiple statements of the same type to check,
7206 * this can happen for example when refinement is being applied, so we just postpone the processing
7207 * and do not duplicate the information */
7208 return EXIT_FAILURE;
Radek Krejci850a5de2016-11-08 14:06:40 +01007209 }
7210 }
7211
Michal Vaskof96dfb62017-08-17 12:23:49 +02007212 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH)) {
7213 /* extension finalization is not even tried when adding the item into the inres list,
7214 * xpath is not tried because it would hide some potential warnings */
Radek Krejcic293bac2017-02-27 11:25:28 +01007215 rc = EXIT_FAILURE;
7216 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007217 prev_ly_errno = ly_errno;
7218 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007219
Michal Vasko53b7da02018-02-13 15:28:42 +01007220 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01007221 if (rc != EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007222 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7223 if (rc != -1) {
7224 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007225 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007226
Radek Krejci80056d52017-01-05 13:13:33 +01007227 if (type == UNRES_LIST_UNIQ) {
7228 /* free the allocated structure */
7229 free(item);
7230 } else if (rc == -1 && type == UNRES_IFFEAT) {
7231 /* free the allocated resources */
7232 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007233 }
Radek Krejci80056d52017-01-05 13:13:33 +01007234 return rc;
7235 } else {
7236 /* erase info about validation errors */
Michal Vasko53b7da02018-02-13 15:28:42 +01007237 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7238 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007239 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007240
Radek Krejci80056d52017-01-05 13:13:33 +01007241 print_unres_schema_item_fail(item, type, snode);
7242
7243 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7244 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7245 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7246 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7247 lyxml_unlink_elem(mod->ctx, yin, 1);
7248 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7249 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007250 }
Michal Vasko88c29542015-11-27 14:57:53 +01007251 }
7252
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007253 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007254 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Michal Vasko53b7da02018-02-13 15:28:42 +01007255 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007256 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007257 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007258 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007259 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007260 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko53b7da02018-02-13 15:28:42 +01007261 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007262 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007263 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01007264 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007265 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007266
Michal Vasko3767fb22016-07-21 12:10:57 +02007267 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007268}
7269
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007270/**
Michal Vaskobb211122015-08-19 14:03:11 +02007271 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007272 *
7273 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007274 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007275 * @param[in] item Old item to be resolved.
7276 * @param[in] type Type of the old unresolved item.
7277 * @param[in] new_item New item to use in the duplicate.
7278 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007279 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007280 */
Michal Vaskodad19402015-08-06 09:51:53 +02007281int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007282unres_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 +02007283{
7284 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007285 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007286 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007287
Michal Vaskocf024702015-10-08 15:01:42 +02007288 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007289
Radek Krejcid09d1a52016-08-11 14:05:45 +02007290 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7291 if (type == UNRES_LIST_UNIQ) {
7292 aux_uniq.list = item;
7293 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7294 item = &aux_uniq;
7295 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007296 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007297
7298 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007299 if (type == UNRES_LIST_UNIQ) {
7300 free(new_item);
7301 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007302 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007303 }
7304
Radek Krejcic79c6b12016-07-26 15:11:49 +02007305 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007306 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007307 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007308 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007309 return -1;
7310 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007311 } else if (type == UNRES_IFFEAT) {
7312 /* duplicate unres_iffeature_data */
7313 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01007314 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007315 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7316 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7317 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007318 LOGINT(mod->ctx);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007319 return -1;
7320 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007321 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007322 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007323 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007324 return -1;
7325 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007326 }
Michal Vaskodad19402015-08-06 09:51:53 +02007327
7328 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007329}
7330
Michal Vaskof02e3742015-08-05 16:27:02 +02007331/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007332int
Michal Vasko878e38d2016-09-05 12:17:53 +02007333unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007334{
Michal Vasko878e38d2016-09-05 12:17:53 +02007335 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007336 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007337
Radek Krejciddddd0d2017-01-20 15:20:46 +01007338 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007339 i = start_on_backwards;
7340 } else {
7341 i = unres->count - 1;
7342 }
7343 for (; i > -1; i--) {
7344 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007345 continue;
7346 }
7347 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007348 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007349 break;
7350 }
7351 } else {
7352 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7353 aux_uniq2 = (struct unres_list_uniq *)item;
7354 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007355 break;
7356 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007357 }
7358 }
7359
Michal Vasko878e38d2016-09-05 12:17:53 +02007360 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007361}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007362
Michal Vaskoede9c472016-06-07 09:38:15 +02007363static void
7364unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7365{
7366 struct lyxml_elem *yin;
7367 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007368 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007369
7370 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007371 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007372 case UNRES_TYPE_DER:
7373 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7374 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7375 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007376 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007377 lydict_remove(ctx, yang->name);
7378 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007379 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7380 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7381 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007382 } else {
7383 lyxml_free(ctx, yin);
7384 }
7385 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007386 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007387 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7388 lydict_remove(ctx, iff_data->fname);
7389 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007390 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007391 case UNRES_IDENT:
7392 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007393 case UNRES_CHOICE_DFLT:
7394 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007395 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7396 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007397 case UNRES_LIST_UNIQ:
7398 free(unres->item[i]);
7399 break;
PavolVicanc1807262017-01-31 18:00:27 +01007400 case UNRES_EXT:
7401 free(unres->str_snode[i]);
7402 break;
PavolVicanfcc98762017-09-01 15:51:39 +02007403 case UNRES_EXT_FINALIZE:
7404 free(unres->str_snode[i]);
Michal Vaskoede9c472016-06-07 09:38:15 +02007405 default:
7406 break;
7407 }
7408 unres->type[i] = UNRES_RESOLVED;
7409}
7410
Michal Vasko88c29542015-11-27 14:57:53 +01007411void
Michal Vasko44ab1462017-05-18 13:18:36 +02007412unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007413{
7414 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007415 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007416
Radek Krejcic071c542016-01-27 14:57:51 +01007417 if (!unres || !(*unres)) {
7418 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007419 }
7420
Michal Vasko44ab1462017-05-18 13:18:36 +02007421 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007422
7423 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007424 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007425 if ((*unres)->type[i] != UNRES_RESOLVED) {
7426 unresolved++;
7427 }
7428 continue;
7429 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007430
7431 /* free heap memory for the specific item */
7432 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007433 }
7434
Michal Vaskoede9c472016-06-07 09:38:15 +02007435 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007436 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007437 free((*unres)->item);
7438 free((*unres)->type);
7439 free((*unres)->str_snode);
7440 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007441 free((*unres));
7442 (*unres) = NULL;
7443 }
Michal Vasko88c29542015-11-27 14:57:53 +01007444}
7445
Michal Vaskoff690e72017-08-03 14:25:07 +02007446/* check whether instance-identifier points outside its data subtree (for operation it is any node
7447 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007448static int
7449check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7450{
Michal Vaskoff690e72017-08-03 14:25:07 +02007451 const struct lys_node *op_node, *first_node;
Michal Vasko53b7da02018-02-13 15:28:42 +01007452 enum int_log_opts prev_ilo;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007453 char *buf;
Michal Vasko53b7da02018-02-13 15:28:42 +01007454 int ret = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007455
Radek Krejci034cb102017-08-01 15:45:13 +02007456 if (!json_instid || !json_instid[0]) {
7457 /* no/empty value */
7458 return 0;
7459 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007460
7461 for (op_node = lys_parent(sleaf);
7462 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7463 op_node = lys_parent(op_node));
7464
7465 if (op_node && lys_parent(op_node)) {
7466 /* nested operation - any absolute path is external */
7467 return 1;
7468 }
7469
7470 /* get the first node from the instid */
7471 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7472 if (!buf) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007473 /* so that we do not have to bother with logging, say it is not external */
7474 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007475 }
7476
Michal Vaskoff690e72017-08-03 14:25:07 +02007477 /* find the first schema node, do not log */
Michal Vasko53b7da02018-02-13 15:28:42 +01007478 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoff690e72017-08-03 14:25:07 +02007479 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
Michal Vasko53b7da02018-02-13 15:28:42 +01007480 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007481
Michal Vasko53b7da02018-02-13 15:28:42 +01007482 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007483 if (!first_node) {
7484 /* unknown path, say it is not external */
Michal Vaskoff690e72017-08-03 14:25:07 +02007485 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007486 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007487
7488 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7489
Michal Vaskoff690e72017-08-03 14:25:07 +02007490 if (op_node && (op_node != first_node)) {
7491 /* it is a top-level operation, so we're good if it points somewhere inside it */
7492 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007493 }
7494
7495 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7496 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007497 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007498}
7499
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007500/**
7501 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7502 *
7503 * @param[in] data Data node where the path is used
7504 * @param[in] path Instance-identifier node value.
7505 * @param[in,out] ret Resolved instance or NULL.
7506 *
7507 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7508 */
7509static int
7510resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7511{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007512 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007513 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007514 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007515 struct lyd_node *root, *node;
Radek Krejcidaa547a2017-09-22 15:56:27 +02007516 const char *model = NULL, *name;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007517 char *str;
7518 int mod_len, name_len, has_predicate;
7519 struct unres_data node_match;
7520
7521 memset(&node_match, 0, sizeof node_match);
7522 *ret = NULL;
7523
7524 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007525 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007526 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007527 if (root->prev) {
7528 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007529 }
7530
7531 /* search for the instance node */
7532 while (path[i]) {
7533 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7534 if (j <= 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007535 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007536 goto error;
7537 }
7538 i += j;
7539
Michal Vasko1b6ca962017-08-03 14:23:09 +02007540 if (model) {
7541 str = strndup(model, mod_len);
7542 if (!str) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007543 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007544 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007545 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02007546 mod = ly_ctx_get_module(ctx, str, NULL, 1);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007547 if (ctx->data_clb) {
7548 if (!mod) {
7549 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7550 } else if (!mod->implemented) {
7551 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7552 }
7553 }
7554 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007555
Michal Vasko1b6ca962017-08-03 14:23:09 +02007556 if (!mod || !mod->implemented || mod->disabled) {
7557 break;
7558 }
7559 } else if (!prev_mod) {
7560 /* first iteration and we are missing module name */
Michal Vaskoaf8ec362018-03-28 09:08:09 +02007561 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
7562 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
Michal Vasko1b6ca962017-08-03 14:23:09 +02007563 goto error;
7564 } else {
7565 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007566 }
7567
Radek Krejci2c822ed2017-08-03 14:23:36 +02007568 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007569 /* no instance exists */
7570 break;
7571 }
7572
7573 if (has_predicate) {
7574 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcidaa547a2017-09-22 15:56:27 +02007575 parsed = j = 0;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007576 /* index of the current node (for lists with position predicates) */
7577 cur_idx = 1;
7578 while (j < (signed)node_match.count) {
7579 node = node_match.node[j];
7580 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7581 if (parsed < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007582 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007583 goto error;
7584 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007585
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007586 if (!node) {
7587 /* current node does not satisfy the predicate */
7588 unres_data_del(&node_match, j);
7589 } else {
7590 ++j;
7591 }
7592 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007593 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007594
7595 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007596 } else if (node_match.count) {
7597 /* check that we are not addressing lists */
7598 for (j = 0; (unsigned)j < node_match.count; ++j) {
7599 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7600 unres_data_del(&node_match, j--);
7601 }
7602 }
7603 if (!node_match.count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007604 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007605 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007606 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007607
7608 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007609 }
7610
7611 if (!node_match.count) {
7612 /* no instance exists */
7613 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007614 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007615 return EXIT_FAILURE;
7616 }
7617 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7618 return EXIT_SUCCESS;
7619 } else if (node_match.count > 1) {
7620 /* instance identifier must resolve to a single node */
Michal Vasko53b7da02018-02-13 15:28:42 +01007621 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007622 goto error;
7623 } else {
7624 /* we have required result, remember it and cleanup */
7625 *ret = node_match.node[0];
7626 free(node_match.node);
7627 return EXIT_SUCCESS;
7628 }
7629
7630error:
7631 /* cleanup */
7632 free(node_match.node);
7633 return -1;
7634}
7635
7636static int
7637resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007638{
Michal Vaskoca16cb32017-07-10 11:50:33 +02007639 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007640 uint32_t i;
7641
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007642 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007643
Michal Vaskoca16cb32017-07-10 11:50:33 +02007644 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007645 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vaskoca16cb32017-07-10 11:50:33 +02007646 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007647 return -1;
7648 }
7649
Michal Vaskoca16cb32017-07-10 11:50:33 +02007650 for (i = 0; i < set->number; ++i) {
7651 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7652 continue;
7653 }
7654
Radek Krejci1899d6a2016-11-03 13:48:07 +01007655 /* not that the value is already in canonical form since the parsers does the conversion,
7656 * so we can simply compare just the values */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007657 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 +01007658 /* we have the match */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007659 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007660 break;
7661 }
7662 }
7663
Michal Vaskoca16cb32017-07-10 11:50:33 +02007664 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007665
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007666 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007667 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007668 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007669 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007670 return EXIT_FAILURE;
7671 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007672 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 +02007673 }
7674 }
7675
7676 return EXIT_SUCCESS;
7677}
7678
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007679/* 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 +01007680int
7681resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7682 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007683{
Michal Vasko53b7da02018-02-13 15:28:42 +01007684 struct ly_ctx *ctx = leaf->schema->module->ctx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007685 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007686 struct lyd_node *ret;
Michal Vasko53b7da02018-02-13 15:28:42 +01007687 enum int_log_opts prev_ilo;
7688 int found, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007689 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007690
7691 assert(type->base == LY_TYPE_UNION);
7692
Michal Vasko70bf8e52018-03-26 11:32:33 +02007693 if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LYTYPE_UNRES))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007694 /* either NULL or instid previously converted to JSON */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007695 json_val = lydict_insert(ctx, leaf->value.string, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007696 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007697
Michal Vaskofd6c6502017-01-06 12:15:41 +01007698 if (store) {
Michal Vasko70bf8e52018-03-26 11:32:33 +02007699 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007700 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007701 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007702
7703 /* 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 +01007704 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007705
7706 t = NULL;
7707 found = 0;
7708 while ((t = lyp_get_next_union_type(type, t, &found))) {
7709 found = 0;
7710
7711 switch (t->base) {
7712 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007713 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7714 req_inst = -1;
7715 } else {
7716 req_inst = t->info.lref.req;
7717 }
7718
7719 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007720 if (store) {
7721 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7722 /* valid resolved */
7723 leaf->value.leafref = ret;
7724 leaf->value_type = LY_TYPE_LEAFREF;
7725 } else {
7726 /* valid unresolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01007727 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko31a2d322018-01-12 13:36:12 +01007728 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007729 return -1;
7730 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007731 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007732 }
7733 }
7734
7735 success = 1;
7736 }
7737 break;
7738 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007739 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7740 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7741 req_inst = -1;
7742 } else {
7743 req_inst = t->info.inst.req;
7744 }
7745
Michal Vaskod3a03112017-01-23 09:56:02 +01007746 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007747 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007748 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007749 /* valid resolved */
7750 leaf->value.instance = ret;
7751 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007752
Michal Vaskofd6c6502017-01-06 12:15:41 +01007753 if (json_val) {
7754 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7755 leaf->value_str = json_val;
7756 json_val = NULL;
7757 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007758 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007759 /* valid unresolved */
7760 if (json_val) {
7761 /* put the JSON val back */
7762 leaf->value.string = json_val;
7763 json_val = NULL;
7764 } else {
7765 leaf->value.instance = NULL;
7766 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02007767 leaf->value_type = LY_TYPE_INST;
7768 leaf->value_flags |= LYTYPE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007769 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007770 }
7771
7772 success = 1;
7773 }
7774 break;
7775 default:
Michal Vasko31a2d322018-01-12 13:36:12 +01007776 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007777 success = 1;
7778 }
7779 break;
7780 }
7781
7782 if (success) {
7783 break;
7784 }
7785
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007786 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007787 if (store) {
Michal Vasko70bf8e52018-03-26 11:32:33 +02007788 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007789 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007790 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007791 }
7792
7793 /* turn logging back on */
Michal Vasko53b7da02018-02-13 15:28:42 +01007794 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007795
7796 if (json_val) {
7797 if (!success) {
7798 /* put the value back for now */
7799 assert(leaf->value_type == LY_TYPE_UNION);
7800 leaf->value.string = json_val;
7801 } else {
7802 /* value was ultimately useless, but we could not have known */
7803 lydict_remove(leaf->schema->module->ctx, json_val);
7804 }
7805 }
7806
Michal Vaskofd6c6502017-01-06 12:15:41 +01007807 if (success) {
7808 if (resolved_type) {
7809 *resolved_type = t;
7810 }
7811 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007812 /* not found and it is required */
Michal Vasko53b7da02018-02-13 15:28:42 +01007813 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007814 return EXIT_FAILURE;
7815 }
7816
7817 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007818
Radek Krejci9b6aad22016-09-20 15:55:51 +02007819}
7820
Michal Vasko8bcdf292015-08-19 14:04:43 +02007821/**
7822 * @brief Resolve a single unres data item. Logs directly.
7823 *
Michal Vaskocf024702015-10-08 15:01:42 +02007824 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007825 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007826 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007827 *
7828 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7829 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007830int
Michal Vasko0b963112017-08-11 12:45:36 +02007831resolve_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 +02007832{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007833 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007834 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007835 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007836 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007837
Michal Vasko83a6c462015-10-08 16:43:53 +02007838 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007839 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007840
Michal Vaskocf024702015-10-08 15:01:42 +02007841 switch (type) {
7842 case UNRES_LEAFREF:
7843 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007844 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007845 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7846 req_inst = -1;
7847 } else {
7848 req_inst = sleaf->type.info.lref.req;
7849 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007850 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7851 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007852 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007853 /* valid resolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02007854 if (leaf->value_type == LY_TYPE_BITS) {
Michal Vasko1c8567a2017-01-05 13:42:27 +01007855 free(leaf->value.bit);
7856 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007857 leaf->value.leafref = ret;
7858 leaf->value_type = LY_TYPE_LEAFREF;
Michal Vasko70bf8e52018-03-26 11:32:33 +02007859 leaf->value_flags &= ~LYTYPE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007860 } else {
7861 /* valid unresolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02007862 if (!(leaf->value_flags & LYTYPE_UNRES)) {
Michal Vasko31a2d322018-01-12 13:36:12 +01007863 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007864 return -1;
7865 }
7866 }
7867 }
7868 leaf->validity &= ~LYD_VAL_LEAFREF;
7869 } else {
7870 return rc;
7871 }
7872 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007873
Michal Vaskocf024702015-10-08 15:01:42 +02007874 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007875 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007876 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7877 if (ext_dep == -1) {
7878 return -1;
7879 }
7880
7881 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7882 req_inst = -1;
7883 } else {
7884 req_inst = sleaf->type.info.inst.req;
7885 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007886 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7887 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007888 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007889 /* valid resolved */
7890 leaf->value.instance = ret;
7891 leaf->value_type = LY_TYPE_INST;
Michal Vasko70bf8e52018-03-26 11:32:33 +02007892 leaf->value_flags &= ~LYTYPE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007893 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007894 /* valid unresolved */
7895 leaf->value.instance = NULL;
Michal Vasko70bf8e52018-03-26 11:32:33 +02007896 leaf->value_type = LY_TYPE_INST;
7897 leaf->value_flags |= LYTYPE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007898 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007899 } else {
7900 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007901 }
Michal Vaskocf024702015-10-08 15:01:42 +02007902 break;
7903
Radek Krejci7de36cf2016-09-12 16:18:50 +02007904 case UNRES_UNION:
7905 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007906 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007907
Michal Vaskocf024702015-10-08 15:01:42 +02007908 case UNRES_WHEN:
Michal Vasko0b963112017-08-11 12:45:36 +02007909 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007910 return rc;
7911 }
7912 break;
7913
Michal Vaskobf19d252015-10-08 15:39:17 +02007914 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007915 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007916 return rc;
7917 }
7918 break;
7919
7920 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007921 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007922 return rc;
7923 }
7924 break;
7925
Michal Vaskocf024702015-10-08 15:01:42 +02007926 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007927 LOGINT(NULL);
Michal Vasko8bcdf292015-08-19 14:04:43 +02007928 return -1;
7929 }
7930
7931 return EXIT_SUCCESS;
7932}
7933
7934/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007935 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007936 *
7937 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007938 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007939 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007940 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007941 */
7942int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007943unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007944{
Radek Krejci03b71f72016-03-16 11:10:09 +01007945 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007946 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007947 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007948
Radek Krejci03b71f72016-03-16 11:10:09 +01007949 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007950 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01007951 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007952 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007953 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007954 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007955 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007956
Radek Krejci0b7704f2016-03-18 12:16:14 +01007957 if (type == UNRES_WHEN) {
7958 /* remove previous result */
7959 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007960 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007961
Michal Vasko53b7da02018-02-13 15:28:42 +01007962 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007963}
7964
7965/**
7966 * @brief Resolve every unres data item in the structure. Logs directly.
7967 *
Michal Vasko660582a2018-03-19 10:10:08 +01007968 * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
7969 * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
7970 * non-presence containers may need to be deleted).
Radek Krejci082c84f2016-10-17 16:33:06 +02007971 *
7972 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7973 *
Michal Vasko53b7da02018-02-13 15:28:42 +01007974 * @param[in] ctx Context used.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007975 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007976 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7977 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007978 *
7979 * @return EXIT_SUCCESS on success, -1 on error.
7980 */
7981int
Michal Vasko53b7da02018-02-13 15:28:42 +01007982resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007983{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007984 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007985 int rc, progress, ignore_fail;
Michal Vasko53b7da02018-02-13 15:28:42 +01007986 enum int_log_opts prev_ilo;
7987 struct ly_err_item *prev_eitem;
mohitarora2489837dc2018-05-01 15:09:36 +05307988 LY_ERR prev_ly_errno = ly_errno;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007989 struct lyd_node *parent;
Michal Vasko0b963112017-08-11 12:45:36 +02007990 struct lys_when *when;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007991
Radek Krejci082c84f2016-10-17 16:33:06 +02007992 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007993 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007994
7995 if (!unres->count) {
7996 return EXIT_SUCCESS;
7997 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007998
Michal Vasko7fa93142018-03-19 09:59:10 +01007999 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008000 ignore_fail = 1;
8001 } else if (options & LYD_OPT_NOEXTDEPS) {
8002 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008003 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008004 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008005 }
8006
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008007 LOGVRB("Resolving unresolved data nodes and their constraints...");
Michal Vasko7fa93142018-03-19 09:59:10 +01008008 if (!ignore_fail) {
8009 /* remember logging state only if errors are generated and valid */
Michal Vasko7fa93142018-03-19 09:59:10 +01008010 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8011 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008012
Michal Vasko7fa93142018-03-19 09:59:10 +01008013 /*
8014 * when-stmt first
8015 */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008016 first = 1;
8017 stmt_count = 0;
8018 resolved = 0;
8019 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01008020 do {
Michal Vasko7fa93142018-03-19 09:59:10 +01008021 if (!ignore_fail) {
8022 ly_err_free_next(ctx, prev_eitem);
8023 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008024 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02008025 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008026 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008027 continue;
8028 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008029 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008030 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008031 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008032 }
8033
8034 /* resolve when condition only when all parent when conditions are already resolved */
8035 for (parent = unres->node[i]->parent;
8036 parent && LYD_WHEN_DONE(parent->when_status);
8037 parent = parent->parent) {
8038 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8039 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02008040 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01008041 */
8042 unres->node[i]->when_status |= LYD_WHEN_FALSE;
8043 unres->type[i] = UNRES_RESOLVED;
8044 resolved++;
8045 break;
8046 }
8047 }
8048 if (parent) {
8049 continue;
8050 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008051
Michal Vasko0b963112017-08-11 12:45:36 +02008052 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01008053 if (!rc) {
Michal Vasko0b963112017-08-11 12:45:36 +02008054 /* finish with error/delete the node only if when was false, an external dependency was not required,
8055 * or it was not provided (the flag would not be passed down otherwise, checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02008056 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vaskoc04173b2018-03-09 10:43:22 +01008057 && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
Radek Krejci082c84f2016-10-17 16:33:06 +02008058 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01008059 /* false when condition */
Michal Vasko53b7da02018-02-13 15:28:42 +01008060 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008061 } /* follows else */
8062
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008063 /* auto-delete */
Michal Vasko53b7da02018-02-13 15:28:42 +01008064 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008065
Radek Krejci0c0086a2016-03-24 15:20:28 +01008066 /* only unlink now, the subtree can contain another nodes stored in the unres list */
8067 /* if it has parent non-presence containers that would be empty, we should actually
8068 * remove the container
8069 */
Radek Krejci2537fd32016-09-07 16:22:41 +02008070 for (parent = unres->node[i];
8071 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8072 parent = parent->parent) {
8073 if (((struct lys_node_container *)parent->parent->schema)->presence) {
8074 /* presence container */
8075 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008076 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008077 if (parent->next || parent->prev != parent) {
8078 /* non empty (the child we are in and we are going to remove is not the only child) */
8079 break;
8080 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008081 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008082 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008083
Radek Krejci0c0086a2016-03-24 15:20:28 +01008084 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008085 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01008086 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008087
Radek Krejci0b7704f2016-03-18 12:16:14 +01008088 lyd_unlink(unres->node[i]);
8089 unres->type[i] = UNRES_DELETE;
8090 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01008091
8092 /* update the rest of unres items */
8093 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01008094 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01008095 continue;
8096 }
8097
8098 /* test if the node is in subtree to be deleted */
8099 for (parent = unres->node[j]; parent; parent = parent->parent) {
8100 if (parent == unres->node[i]) {
8101 /* yes, it is */
8102 unres->type[j] = UNRES_RESOLVED;
8103 resolved++;
8104 break;
8105 }
8106 }
8107 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008108 } else {
8109 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01008110 }
Michal Vasko7fa93142018-03-19 09:59:10 +01008111 if (!ignore_fail) {
8112 ly_err_free_next(ctx, prev_eitem);
8113 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008114 resolved++;
8115 progress = 1;
8116 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008117 goto error;
Radek Krejci2467a492016-10-24 15:16:59 +02008118 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01008119 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008120 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008121 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01008122
Radek Krejci0b7704f2016-03-18 12:16:14 +01008123 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008124 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008125 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008126 }
8127
8128 for (i = 0; del_items && i < unres->count; i++) {
8129 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8130 if (unres->type[i] != UNRES_DELETE) {
8131 continue;
8132 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008133 if (!unres->node[i]) {
8134 unres->type[i] = UNRES_RESOLVED;
8135 del_items--;
8136 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008137 }
8138
8139 /* really remove the complete subtree */
8140 lyd_free(unres->node[i]);
8141 unres->type[i] = UNRES_RESOLVED;
8142 del_items--;
8143 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008144
Michal Vasko7fa93142018-03-19 09:59:10 +01008145 /*
8146 * now leafrefs
8147 */
8148 if (options & LYD_OPT_TRUSTED) {
8149 /* we want to attempt to resolve leafrefs */
8150 assert(!ignore_fail);
8151 ignore_fail = 1;
8152
8153 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8154 ly_errno = prev_ly_errno;
8155 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008156 first = 1;
8157 stmt_count = 0;
8158 resolved = 0;
8159 do {
8160 progress = 0;
8161 for (i = 0; i < unres->count; i++) {
8162 if (unres->type[i] != UNRES_LEAFREF) {
8163 continue;
8164 }
8165 if (first) {
8166 /* count leafref nodes in unres list */
8167 stmt_count++;
8168 }
8169
Michal Vasko0b963112017-08-11 12:45:36 +02008170 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008171 if (!rc) {
8172 unres->type[i] = UNRES_RESOLVED;
Michal Vasko7fa93142018-03-19 09:59:10 +01008173 if (!ignore_fail) {
8174 ly_err_free_next(ctx, prev_eitem);
8175 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008176 resolved++;
8177 progress = 1;
8178 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008179 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008180 } /* else forward reference */
8181 }
8182 first = 0;
8183 } while (progress && resolved < stmt_count);
8184
8185 /* do we have some unresolved leafrefs? */
8186 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008187 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008188 }
8189
Michal Vasko7fa93142018-03-19 09:59:10 +01008190 if (!ignore_fail) {
8191 /* log normally now, throw away irrelevant errors */
8192 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8193 ly_errno = prev_ly_errno;
8194 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008195
Michal Vasko7fa93142018-03-19 09:59:10 +01008196 /*
8197 * rest
8198 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008199 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008200 if (unres->type[i] == UNRES_RESOLVED) {
8201 continue;
8202 }
Radek Krejci082c84f2016-10-17 16:33:06 +02008203 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01008204
Michal Vasko0b963112017-08-11 12:45:36 +02008205 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008206 if (rc) {
8207 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008208 return -1;
8209 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008210
8211 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008212 }
8213
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008214 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01008215 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008216 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01008217
8218error:
Michal Vasko7fa93142018-03-19 09:59:10 +01008219 if (!ignore_fail) {
8220 /* print all the new errors */
8221 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8222 /* do not restore ly_errno, it was udpated properly */
8223 }
Michal Vasko53b7da02018-02-13 15:28:42 +01008224 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008225}