blob: d5927ba94c1be38b6cd13463388a40c0e689fa76 [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 Vasko185b5272018-09-13 14:26:12 +020033#include "validation.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020034
Michal Vasko2d44ee02018-05-18 09:38:51 +020035/* internal parsed predicate structure */
36struct parsed_pred {
37 const struct lys_node *schema;
Michal Vaskoc340b3d2020-06-29 10:47:11 +020038 const char *pred_str;
39 int pred_str_len;
40
Michal Vasko2d44ee02018-05-18 09:38:51 +020041 int len;
42 struct {
43 const char *mod_name;
44 int mod_name_len;
45 const char *name;
46 int nam_len;
47 const char *value;
48 int val_len;
49 } *pred;
50};
51
Michal Vaskod24dd012016-09-30 12:20:22 +020052int
53parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020054{
55 const char *ptr;
56 int minus = 0;
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020057 int64_t ret = 0, prev_ret;
Radek Krejcibf47a822016-11-04 10:06:08 +010058 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020059
60 ptr = *str_num;
61
62 if (ptr[0] == '-') {
63 minus = 1;
64 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010065 } else if (ptr[0] == '+') {
66 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020067 }
68
Michal Vaskod24dd012016-09-30 12:20:22 +020069 if (!isdigit(ptr[0])) {
70 /* there must be at least one */
71 return 1;
72 }
73
Michal Vasko4d1f0482016-09-19 14:35:06 +020074 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
75 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020076 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020077 }
78
79 if (ptr[0] == '.') {
80 if (ptr[1] == '.') {
81 /* it's the next interval */
82 break;
83 }
84 ++str_dig;
85 } else {
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020086 prev_ret = ret;
87 if (minus) {
88 ret = ret * 10 - (ptr[0] - '0');
89 if (ret > prev_ret) {
90 return 1;
91 }
92 } else {
93 ret = ret * 10 + (ptr[0] - '0');
94 if (ret < prev_ret) {
95 return 1;
96 }
97 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020098 if (str_dig > -1) {
99 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +0100100 if (ptr[0] == '0') {
101 /* possibly trailing zero */
102 trailing_zeros++;
103 } else {
104 trailing_zeros = 0;
105 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200106 }
107 ++str_exp;
108 }
109 }
Michal Vaskod24dd012016-09-30 12:20:22 +0200110 if (str_dig == 0) {
111 /* no digits after '.' */
112 return 1;
113 } else if (str_dig == -1) {
114 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +0200115 str_dig = 0;
116 }
Radek Krejcibf47a822016-11-04 10:06:08 +0100117 /* remove trailing zeros */
118 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +0100119 str_dig -= trailing_zeros;
120 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +0100121 ret = ret / dec_pow(trailing_zeros);
122 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200123
124 /* it's parsed, now adjust the number based on fraction-digits, if needed */
125 if (str_dig < dig) {
126 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200127 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200128 }
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200129 prev_ret = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200130 ret *= dec_pow(dig - str_dig);
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200131 if ((minus && (ret > prev_ret)) || (!minus && (ret < prev_ret))) {
132 return 1;
133 }
134
Michal Vasko4d1f0482016-09-19 14:35:06 +0200135 }
136 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200137 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200138 }
139
Michal Vasko4d1f0482016-09-19 14:35:06 +0200140 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200141 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200142
Michal Vaskod24dd012016-09-30 12:20:22 +0200143 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200144}
145
146/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200147 * @brief Parse an identifier.
148 *
149 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
150 * identifier = (ALPHA / "_")
151 * *(ALPHA / DIGIT / "_" / "-" / ".")
152 *
Michal Vaskobb211122015-08-19 14:03:11 +0200153 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200154 *
155 * @return Number of characters successfully parsed.
156 */
Radek Krejcidce5f972017-09-12 15:47:49 +0200157unsigned int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200158parse_identifier(const char *id)
159{
Radek Krejcidce5f972017-09-12 15:47:49 +0200160 unsigned int parsed = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200161
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100162 assert(id);
163
Radek Krejci6dc53a22015-08-17 13:27:59 +0200164 if (!isalpha(id[0]) && (id[0] != '_')) {
165 return -parsed;
166 }
167
168 ++parsed;
169 ++id;
170
171 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
172 ++parsed;
173 ++id;
174 }
175
176 return parsed;
177}
178
179/**
180 * @brief Parse a node-identifier.
181 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200182 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200183 *
Michal Vaskobb211122015-08-19 14:03:11 +0200184 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200185 * @param[out] mod_name Points to the module name, NULL if there is not any.
186 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200187 * @param[out] name Points to the node name.
188 * @param[out] nam_len Length of the node name.
Michal Vasko50576712017-07-28 12:28:33 +0200189 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
PavolVicanb28bbff2018-02-21 00:44:02 +0100190 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200191 *
192 * @return Number of characters successfully parsed,
193 * positive on success, negative on failure.
194 */
195static int
Michal Vasko50576712017-07-28 12:28:33 +0200196parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
197 int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200198{
Michal Vasko299961d2019-02-18 10:20:51 +0100199 int parsed = 0, ret, all_desc_local = 0, first_id_len;
200 const char *first_id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200201
202 assert(id);
Michal Vasko50576712017-07-28 12:28:33 +0200203 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
204 assert((name && nam_len) || (!name && !nam_len));
Michal Vasko50576712017-07-28 12:28:33 +0200205
Michal Vasko723e50c2015-10-20 15:20:29 +0200206 if (mod_name) {
207 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200208 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200209 }
210 if (name) {
211 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200212 *nam_len = 0;
213 }
214
Michal Vasko50576712017-07-28 12:28:33 +0200215 if (extended) {
216 /* try to parse only the extended expressions */
217 if (id[parsed] == '/') {
PavolVican195cf392018-02-23 13:24:45 +0100218 if (all_desc) {
219 *all_desc = 1;
220 }
221 all_desc_local = 1;
Michal Vasko50576712017-07-28 12:28:33 +0200222 } else {
PavolVican195cf392018-02-23 13:24:45 +0100223 if (all_desc) {
224 *all_desc = 0;
225 }
Michal Vasko50576712017-07-28 12:28:33 +0200226 }
227
228 /* is there a prefix? */
PavolVican195cf392018-02-23 13:24:45 +0100229 ret = parse_identifier(id + all_desc_local);
Michal Vasko50576712017-07-28 12:28:33 +0200230 if (ret > 0) {
PavolVican195cf392018-02-23 13:24:45 +0100231 if (id[all_desc_local + ret] != ':') {
Michal Vasko50576712017-07-28 12:28:33 +0200232 /* this is not a prefix, so not an extended id */
233 goto standard_id;
234 }
235
236 if (mod_name) {
PavolVican195cf392018-02-23 13:24:45 +0100237 *mod_name = id + all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200238 *mod_name_len = ret;
239 }
240
241 /* "/" and ":" */
PavolVican195cf392018-02-23 13:24:45 +0100242 ret += all_desc_local + 1;
Michal Vasko50576712017-07-28 12:28:33 +0200243 } else {
PavolVican195cf392018-02-23 13:24:45 +0100244 ret = all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200245 }
246
247 /* parse either "*" or "." */
PavolVicanb28bbff2018-02-21 00:44:02 +0100248 if (*(id + ret) == '*') {
Michal Vasko50576712017-07-28 12:28:33 +0200249 if (name) {
250 *name = id + ret;
251 *nam_len = 1;
252 }
253 ++ret;
254
255 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100256 } else if (*(id + ret) == '.') {
PavolVican195cf392018-02-23 13:24:45 +0100257 if (!all_desc_local) {
Michal Vasko50576712017-07-28 12:28:33 +0200258 /* /. is redundant expression, we do not accept it */
259 return -ret;
260 }
261
262 if (name) {
263 *name = id + ret;
264 *nam_len = 1;
265 }
266 ++ret;
267
268 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100269 } else if (*(id + ret) == '#') {
PavolVican195cf392018-02-23 13:24:45 +0100270 if (all_desc_local || !ret) {
PavolVicanb28bbff2018-02-21 00:44:02 +0100271 /* no prefix */
272 return 0;
273 }
274 parsed = ret + 1;
275 if ((ret = parse_identifier(id + parsed)) < 1) {
276 return -parsed + ret;
277 }
278 *name = id + parsed - 1;
279 *nam_len = ret + 1;
280 return parsed + ret;
Michal Vasko50576712017-07-28 12:28:33 +0200281 }
282 /* else a standard id, parse it all again */
283 }
284
285standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200286 if ((ret = parse_identifier(id)) < 1) {
287 return ret;
288 }
289
Michal Vasko299961d2019-02-18 10:20:51 +0100290 first_id = id;
291 first_id_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200292
293 parsed += ret;
294 id += ret;
295
296 /* there is prefix */
297 if (id[0] == ':') {
298 ++parsed;
299 ++id;
300
301 /* there isn't */
302 } else {
Michal Vasko299961d2019-02-18 10:20:51 +0100303 if (name) {
304 *name = first_id;
305 *nam_len = first_id_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200306 }
307
308 return parsed;
309 }
310
311 /* identifier (node name) */
312 if ((ret = parse_identifier(id)) < 1) {
Michal Vasko299961d2019-02-18 10:20:51 +0100313 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200314 }
315
Michal Vasko299961d2019-02-18 10:20:51 +0100316 if (mod_name) {
317 *mod_name = first_id;
318 *mod_name_len = first_id_len;
319 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200320 if (name) {
321 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200322 *nam_len = ret;
323 }
324
Michal Vasko299961d2019-02-18 10:20:51 +0100325 return parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200326}
327
328/**
329 * @brief Parse a path-predicate (leafref).
330 *
331 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
332 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
333 *
Michal Vaskobb211122015-08-19 14:03:11 +0200334 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200335 * @param[out] prefix Points to the prefix, NULL if there is not any.
336 * @param[out] pref_len Length of the prefix, 0 if there is not any.
337 * @param[out] name Points to the node name.
338 * @param[out] nam_len Length of the node name.
339 * @param[out] path_key_expr Points to the path-key-expr.
340 * @param[out] pke_len Length of the path-key-expr.
341 * @param[out] has_predicate Flag to mark whether there is another predicate following.
342 *
343 * @return Number of characters successfully parsed,
344 * positive on success, negative on failure.
345 */
346static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200347parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
348 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200349{
350 const char *ptr;
351 int parsed = 0, ret;
352
353 assert(id);
354 if (prefix) {
355 *prefix = NULL;
356 }
357 if (pref_len) {
358 *pref_len = 0;
359 }
360 if (name) {
361 *name = NULL;
362 }
363 if (nam_len) {
364 *nam_len = 0;
365 }
366 if (path_key_expr) {
367 *path_key_expr = NULL;
368 }
369 if (pke_len) {
370 *pke_len = 0;
371 }
372 if (has_predicate) {
373 *has_predicate = 0;
374 }
375
376 if (id[0] != '[') {
377 return -parsed;
378 }
379
380 ++parsed;
381 ++id;
382
383 while (isspace(id[0])) {
384 ++parsed;
385 ++id;
386 }
387
Michal Vasko50576712017-07-28 12:28:33 +0200388 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci29e85282019-06-10 09:11:10 +0200389 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200390 }
391
392 parsed += ret;
393 id += ret;
394
395 while (isspace(id[0])) {
396 ++parsed;
397 ++id;
398 }
399
400 if (id[0] != '=') {
401 return -parsed;
402 }
403
404 ++parsed;
405 ++id;
406
407 while (isspace(id[0])) {
408 ++parsed;
409 ++id;
410 }
411
412 if ((ptr = strchr(id, ']')) == NULL) {
413 return -parsed;
414 }
415
416 --ptr;
417 while (isspace(ptr[0])) {
418 --ptr;
419 }
420 ++ptr;
421
422 ret = ptr-id;
423 if (path_key_expr) {
424 *path_key_expr = id;
425 }
426 if (pke_len) {
427 *pke_len = ret;
428 }
429
430 parsed += ret;
431 id += ret;
432
433 while (isspace(id[0])) {
434 ++parsed;
435 ++id;
436 }
437
438 assert(id[0] == ']');
439
440 if (id[1] == '[') {
441 *has_predicate = 1;
442 }
443
444 return parsed+1;
445}
446
447/**
448 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
449 * the ".." and the first node-identifier, other calls parse a single
450 * node-identifier each.
451 *
452 * path-key-expr = current-function-invocation *WSP "/" *WSP
453 * rel-path-keyexpr
454 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
455 * *(node-identifier *WSP "/" *WSP)
456 * node-identifier
457 *
Michal Vaskobb211122015-08-19 14:03:11 +0200458 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200459 * @param[out] prefix Points to the prefix, NULL if there is not any.
460 * @param[out] pref_len Length of the prefix, 0 if there is not any.
461 * @param[out] name Points to the node name.
462 * @param[out] nam_len Length of the node name.
463 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
464 * must not be changed between consecutive calls.
465 * @return Number of characters successfully parsed,
466 * positive on success, negative on failure.
467 */
468static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200469parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
470 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200471{
472 int parsed = 0, ret, par_times = 0;
473
474 assert(id);
475 assert(parent_times);
476 if (prefix) {
477 *prefix = NULL;
478 }
479 if (pref_len) {
480 *pref_len = 0;
481 }
482 if (name) {
483 *name = NULL;
484 }
485 if (nam_len) {
486 *nam_len = 0;
487 }
488
489 if (!*parent_times) {
490 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
491 if (strncmp(id, "current()", 9)) {
492 return -parsed;
493 }
494
495 parsed += 9;
496 id += 9;
497
498 while (isspace(id[0])) {
499 ++parsed;
500 ++id;
501 }
502
503 if (id[0] != '/') {
504 return -parsed;
505 }
506
507 ++parsed;
508 ++id;
509
510 while (isspace(id[0])) {
511 ++parsed;
512 ++id;
513 }
514
515 /* rel-path-keyexpr */
516 if (strncmp(id, "..", 2)) {
517 return -parsed;
518 }
519 ++par_times;
520
521 parsed += 2;
522 id += 2;
523
524 while (isspace(id[0])) {
525 ++parsed;
526 ++id;
527 }
528 }
529
530 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
531 *
532 * first parent reference with whitespaces already parsed
533 */
534 if (id[0] != '/') {
535 return -parsed;
536 }
537
538 ++parsed;
539 ++id;
540
541 while (isspace(id[0])) {
542 ++parsed;
543 ++id;
544 }
545
546 while (!strncmp(id, "..", 2) && !*parent_times) {
547 ++par_times;
548
549 parsed += 2;
550 id += 2;
551
552 while (isspace(id[0])) {
553 ++parsed;
554 ++id;
555 }
556
557 if (id[0] != '/') {
558 return -parsed;
559 }
560
561 ++parsed;
562 ++id;
563
564 while (isspace(id[0])) {
565 ++parsed;
566 ++id;
567 }
568 }
569
570 if (!*parent_times) {
571 *parent_times = par_times;
572 }
573
574 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200575 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
576 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200577 }
578
579 parsed += ret;
580 id += ret;
581
582 return parsed;
583}
584
585/**
586 * @brief Parse path-arg (leafref).
587 *
588 * path-arg = absolute-path / relative-path
589 * absolute-path = 1*("/" (node-identifier *path-predicate))
590 * relative-path = 1*(".." "/") descendant-path
591 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200592 * @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 +0200593 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200594 * @param[out] prefix Points to the prefix, NULL if there is not any.
595 * @param[out] pref_len Length of the prefix, 0 if there is not any.
596 * @param[out] name Points to the node name.
597 * @param[out] nam_len Length of the node name.
598 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
599 * must not be changed between consecutive calls. -1 if the
600 * path is relative.
601 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
602 *
603 * @return Number of characters successfully parsed,
604 * positive on success, negative on failure.
605 */
606static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200607parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200608 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200609{
610 int parsed = 0, ret, par_times = 0;
611
612 assert(id);
613 assert(parent_times);
614 if (prefix) {
615 *prefix = NULL;
616 }
617 if (pref_len) {
618 *pref_len = 0;
619 }
620 if (name) {
621 *name = NULL;
622 }
623 if (nam_len) {
624 *nam_len = 0;
625 }
626 if (has_predicate) {
627 *has_predicate = 0;
628 }
629
630 if (!*parent_times && !strncmp(id, "..", 2)) {
631 ++par_times;
632
633 parsed += 2;
634 id += 2;
635
636 while (!strncmp(id, "/..", 3)) {
637 ++par_times;
638
639 parsed += 3;
640 id += 3;
641 }
642 }
643
644 if (!*parent_times) {
645 if (par_times) {
646 *parent_times = par_times;
647 } else {
648 *parent_times = -1;
649 }
650 }
651
652 if (id[0] != '/') {
653 return -parsed;
654 }
655
656 /* skip '/' */
657 ++parsed;
658 ++id;
659
660 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200661 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci29e85282019-06-10 09:11:10 +0200662 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200663 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200664 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200665 /* actually we always need prefix even it is not specified */
666 *prefix = lys_main_module(mod)->name;
667 *pref_len = strlen(*prefix);
668 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200669
670 parsed += ret;
671 id += ret;
672
673 /* there is no predicate */
674 if ((id[0] == '/') || !id[0]) {
675 return parsed;
676 } else if (id[0] != '[') {
677 return -parsed;
678 }
679
680 if (has_predicate) {
681 *has_predicate = 1;
682 }
683
684 return parsed;
685}
686
687/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200688 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200689 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200690 *
691 * instance-identifier = 1*("/" (node-identifier *predicate))
692 *
Michal Vaskobb211122015-08-19 14:03:11 +0200693 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200694 * @param[out] model Points to the model name.
695 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200696 * @param[out] name Points to the node name.
697 * @param[out] nam_len Length of the node name.
698 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
699 *
700 * @return Number of characters successfully parsed,
701 * positive on success, negative on failure.
702 */
703static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200704parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
705 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200706{
707 int parsed = 0, ret;
708
Michal Vasko1b6ca962017-08-03 14:23:09 +0200709 assert(id && model && mod_len && name && nam_len);
710
Radek Krejci6dc53a22015-08-17 13:27:59 +0200711 if (has_predicate) {
712 *has_predicate = 0;
713 }
714
715 if (id[0] != '/') {
716 return -parsed;
717 }
718
719 ++parsed;
720 ++id;
721
Michal Vaskob2f40be2016-09-08 16:03:48 +0200722 if ((ret = parse_identifier(id)) < 1) {
723 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200724 }
725
Michal Vaskob2f40be2016-09-08 16:03:48 +0200726 *name = id;
727 *nam_len = ret;
728
Michal Vasko8db018b2020-01-09 11:01:02 +0100729 *model = NULL;
730 *mod_len = 0;
731
Michal Vaskob2f40be2016-09-08 16:03:48 +0200732 parsed += ret;
733 id += ret;
734
Michal Vasko1b6ca962017-08-03 14:23:09 +0200735 if (id[0] == ':') {
736 /* we have prefix */
737 *model = *name;
738 *mod_len = *nam_len;
739
740 ++parsed;
741 ++id;
742
743 if ((ret = parse_identifier(id)) < 1) {
744 return ret;
745 }
746
747 *name = id;
748 *nam_len = ret;
749
750 parsed += ret;
751 id += ret;
752 }
753
Radek Krejci4967cb62016-09-14 16:40:28 +0200754 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200755 *has_predicate = 1;
756 }
757
758 return parsed;
759}
760
761/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200762 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200763 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200764 *
765 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
766 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
767 * ((DQUOTE string DQUOTE) /
768 * (SQUOTE string SQUOTE))
769 * pos = non-negative-integer-value
770 *
Michal Vaskobb211122015-08-19 14:03:11 +0200771 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200772 * @param[out] model Points to the model name.
773 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200774 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
775 * @param[out] nam_len Length of the node name.
776 * @param[out] value Value the node-identifier must have (string from the grammar),
777 * NULL if there is not any.
778 * @param[out] val_len Length of the value, 0 if there is not any.
779 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
780 *
781 * @return Number of characters successfully parsed,
782 * positive on success, negative on failure.
783 */
784static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200785parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
786 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200787{
788 const char *ptr;
789 int parsed = 0, ret;
790 char quote;
791
792 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200793 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200794 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200795 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200796 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200797 }
798 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200799 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200800 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200801 *nam_len = 0;
802 }
803 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200804 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200805 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200806 *val_len = 0;
807 }
808 if (has_predicate) {
809 *has_predicate = 0;
810 }
811
812 if (id[0] != '[') {
813 return -parsed;
814 }
815
816 ++parsed;
817 ++id;
818
819 while (isspace(id[0])) {
820 ++parsed;
821 ++id;
822 }
823
824 /* pos */
825 if (isdigit(id[0])) {
826 if (name) {
827 *name = id;
828 }
829
830 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200831 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200832 }
833
834 while (isdigit(id[0])) {
835 ++parsed;
836 ++id;
837 }
838
839 if (nam_len) {
840 *nam_len = id-(*name);
841 }
842
Michal Vaskof2f28a12016-09-09 12:43:06 +0200843 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200844 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200845 if (id[0] == '.') {
846 if (name) {
847 *name = id;
848 }
849 if (nam_len) {
850 *nam_len = 1;
851 }
852
853 ++parsed;
854 ++id;
855
856 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200857 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200858 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200859 }
860
861 parsed += ret;
862 id += ret;
863 }
864
865 while (isspace(id[0])) {
866 ++parsed;
867 ++id;
868 }
869
870 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200871 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200872 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200873
Radek Krejci6dc53a22015-08-17 13:27:59 +0200874 ++parsed;
875 ++id;
876
Michal Vaskof2f28a12016-09-09 12:43:06 +0200877 while (isspace(id[0])) {
878 ++parsed;
879 ++id;
880 }
881
882 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
883 if ((id[0] == '\"') || (id[0] == '\'')) {
884 quote = id[0];
885
886 ++parsed;
887 ++id;
888
889 if ((ptr = strchr(id, quote)) == NULL) {
890 return -parsed;
891 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200892 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200893
894 if (value) {
895 *value = id;
896 }
897 if (val_len) {
898 *val_len = ret;
899 }
900
Michal Vasko1b6ca962017-08-03 14:23:09 +0200901 parsed += ret + 1;
902 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200903 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200904 return -parsed;
905 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200906 }
907
908 while (isspace(id[0])) {
909 ++parsed;
910 ++id;
911 }
912
913 if (id[0] != ']') {
914 return -parsed;
915 }
916
917 ++parsed;
918 ++id;
919
920 if ((id[0] == '[') && has_predicate) {
921 *has_predicate = 1;
922 }
923
924 return parsed;
925}
926
927/**
928 * @brief Parse schema-nodeid.
929 *
930 * schema-nodeid = absolute-schema-nodeid /
931 * descendant-schema-nodeid
932 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200933 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200934 * node-identifier
935 * absolute-schema-nodeid
936 *
Michal Vaskobb211122015-08-19 14:03:11 +0200937 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200938 * @param[out] mod_name Points to the module name, NULL if there is not any.
939 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200940 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200941 * @param[out] nam_len Length of the node name.
942 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
943 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100944 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
945 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200946 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200947 *
948 * @return Number of characters successfully parsed,
949 * positive on success, negative on failure.
950 */
Michal Vasko22448d32016-03-16 13:17:29 +0100951int
Michal Vasko723e50c2015-10-20 15:20:29 +0200952parse_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 +0200953 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200954{
955 int parsed = 0, ret;
956
957 assert(id);
958 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200959
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100960 if (has_predicate) {
961 *has_predicate = 0;
962 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200963
964 if (id[0] != '/') {
965 if (*is_relative != -1) {
966 return -parsed;
967 } else {
968 *is_relative = 1;
969 }
Michal Vasko48935352016-03-29 11:52:36 +0200970 if (!strncmp(id, "./", 2)) {
971 parsed += 2;
972 id += 2;
973 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200974 } else {
975 if (*is_relative == -1) {
976 *is_relative = 0;
977 }
978 ++parsed;
979 ++id;
980 }
981
Michal Vasko50576712017-07-28 12:28:33 +0200982 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
983 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200984 }
985
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100986 parsed += ret;
987 id += ret;
988
989 if ((id[0] == '[') && has_predicate) {
990 *has_predicate = 1;
991 }
992
993 return parsed;
994}
995
996/**
997 * @brief Parse schema predicate (special format internally used).
998 *
999 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001000 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001001 * key-with-value = identifier *WSP "=" *WSP
1002 * ((DQUOTE string DQUOTE) /
1003 * (SQUOTE string SQUOTE))
1004 *
1005 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001006 * @param[out] mod_name Points to the list key module name.
1007 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001008 * @param[out] name Points to the list key name.
1009 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +01001010 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001011 * @param[out] val_len Length of \p value.
1012 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
1013 */
Michal Vasko22448d32016-03-16 13:17:29 +01001014int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001015parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1016 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001017{
1018 const char *ptr;
1019 int parsed = 0, ret;
1020 char quote;
1021
1022 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001023 if (mod_name) {
1024 *mod_name = NULL;
1025 }
1026 if (mod_name_len) {
1027 *mod_name_len = 0;
1028 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001029 if (name) {
1030 *name = NULL;
1031 }
1032 if (nam_len) {
1033 *nam_len = 0;
1034 }
1035 if (value) {
1036 *value = NULL;
1037 }
1038 if (val_len) {
1039 *val_len = 0;
1040 }
1041 if (has_predicate) {
1042 *has_predicate = 0;
1043 }
1044
1045 if (id[0] != '[') {
1046 return -parsed;
1047 }
1048
1049 ++parsed;
1050 ++id;
1051
1052 while (isspace(id[0])) {
1053 ++parsed;
1054 ++id;
1055 }
1056
Michal Vasko22448d32016-03-16 13:17:29 +01001057 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001058 if (id[0] == '.') {
1059 ret = 1;
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 Vasko58c2aab2017-01-05 10:02:05 +01001067 } else if (isdigit(id[0])) {
1068 if (id[0] == '0') {
1069 return -parsed;
1070 }
1071 ret = 1;
1072 while (isdigit(id[ret])) {
1073 ++ret;
1074 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001075
1076 if (name) {
1077 *name = id;
1078 }
1079 if (nam_len) {
1080 *nam_len = ret;
1081 }
Michal Vasko50576712017-07-28 12:28:33 +02001082 } 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 +01001083 return -parsed + ret;
1084 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001085
1086 parsed += ret;
1087 id += ret;
1088
1089 while (isspace(id[0])) {
1090 ++parsed;
1091 ++id;
1092 }
1093
1094 /* there is value as well */
1095 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001096 if (name && isdigit(**name)) {
1097 return -parsed;
1098 }
1099
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001100 ++parsed;
1101 ++id;
1102
1103 while (isspace(id[0])) {
1104 ++parsed;
1105 ++id;
1106 }
1107
1108 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1109 if ((id[0] == '\"') || (id[0] == '\'')) {
1110 quote = id[0];
1111
1112 ++parsed;
1113 ++id;
1114
1115 if ((ptr = strchr(id, quote)) == NULL) {
1116 return -parsed;
1117 }
1118 ret = ptr - id;
1119
1120 if (value) {
1121 *value = id;
1122 }
1123 if (val_len) {
1124 *val_len = ret;
1125 }
1126
1127 parsed += ret + 1;
1128 id += ret + 1;
1129 } else {
1130 return -parsed;
1131 }
1132
1133 while (isspace(id[0])) {
1134 ++parsed;
1135 ++id;
1136 }
1137 }
1138
1139 if (id[0] != ']') {
1140 return -parsed;
1141 }
1142
1143 ++parsed;
1144 ++id;
1145
1146 if ((id[0] == '[') && has_predicate) {
1147 *has_predicate = 1;
1148 }
1149
1150 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001151}
1152
Michal Vasko2d44ee02018-05-18 09:38:51 +02001153static struct lyd_node *
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001154resolve_json_data_node_hash(struct lyd_node *siblings, struct parsed_pred pp)
Michal Vasko2d44ee02018-05-18 09:38:51 +02001155{
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001156 struct lyd_node *ret = NULL;
1157 char *key_or_value = NULL;
Michal Vasko2d44ee02018-05-18 09:38:51 +02001158
Michal Vasko2d44ee02018-05-18 09:38:51 +02001159 if (pp.schema->nodetype == LYS_LEAFLIST) {
1160 assert((pp.len == 1) && (pp.pred[0].name[0] == '.') && (pp.pred[0].nam_len == 1));
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001161
1162 key_or_value = strndup(pp.pred[0].value, pp.pred[0].val_len);
Michal Vasko2d44ee02018-05-18 09:38:51 +02001163 } else if (pp.schema->nodetype == LYS_LIST) {
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001164 key_or_value = strndup(pp.pred_str, pp.pred_str_len);
Michal Vasko2d44ee02018-05-18 09:38:51 +02001165 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02001166
1167 /* try to find the node */
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001168 lyd_find_sibling_val(siblings, pp.schema, key_or_value, &ret);
1169 free(key_or_value);
Michal Vasko2d44ee02018-05-18 09:38:51 +02001170
Michal Vaskoc340b3d2020-06-29 10:47:11 +02001171 return ret;
Michal Vasko2d44ee02018-05-18 09:38:51 +02001172}
1173
Radek Krejci6dc53a22015-08-17 13:27:59 +02001174/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001175 * @brief Resolve (find) a feature definition. Logs directly.
1176 *
1177 * @param[in] feat_name Feature name to resolve.
1178 * @param[in] len Length of \p feat_name.
1179 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001180 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1181 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001182 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001183 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001184 */
1185static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001186resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001187{
1188 char *str;
1189 const char *mod_name, *name;
1190 int mod_name_len, nam_len, i, j;
1191 const struct lys_module *module;
1192
Radek Krejci9ff0a922016-07-14 13:08:05 +02001193 assert(feature);
1194
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001195 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001196 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 +01001197 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001198 return -1;
1199 }
1200
Michal Vasko921eb6b2017-10-13 10:01:39 +02001201 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001202 if (!module) {
1203 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01001204 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001205 return -1;
1206 }
1207
Radek Krejci9ff0a922016-07-14 13:08:05 +02001208 if (module != node->module && module == lys_node_module(node)) {
1209 /* first, try to search directly in submodule where the feature was mentioned */
1210 for (j = 0; j < node->module->features_size; j++) {
1211 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1212 /* check status */
1213 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001214 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001215 return -1;
1216 }
1217 *feature = &node->module->features[j];
1218 return 0;
1219 }
1220 }
1221 }
1222
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001223 /* search in the identified module ... */
1224 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001225 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001226 /* check status */
1227 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001228 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001229 return -1;
1230 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001231 *feature = &module->features[j];
1232 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001233 }
1234 }
1235 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001236 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001237 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001238 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1239 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001240 /* check status */
1241 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1242 module->inc[i].submodule->features[j].flags,
1243 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001244 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001245 return -1;
1246 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001247 *feature = &module->inc[i].submodule->features[j];
1248 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001249 }
1250 }
1251 }
1252
1253 /* not found */
1254 str = strndup(feat_name, len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001255 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001256 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001257 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001258}
1259
Radek Krejci9ff0a922016-07-14 13:08:05 +02001260/*
1261 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001262 * - 1 if enabled
1263 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001264 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001265static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001266resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001267{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001268 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001269
Radek Krejci9ff0a922016-07-14 13:08:05 +02001270 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001271 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001272 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001273 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001274 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001275
Radek Krejci69b8d922016-07-27 13:13:41 +02001276 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001277}
1278
1279static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001281{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001282 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001283 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001284
Radek Krejci9ff0a922016-07-14 13:08:05 +02001285 op = iff_getop(expr->expr, *index_e);
1286 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001287
Radek Krejci9ff0a922016-07-14 13:08:05 +02001288 switch (op) {
1289 case LYS_IFF_F:
1290 /* resolve feature */
1291 return resolve_feature_value(expr->features[(*index_f)++]);
1292 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001293 /* invert result */
1294 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001295 case LYS_IFF_AND:
1296 case LYS_IFF_OR:
1297 a = resolve_iffeature_recursive(expr, index_e, index_f);
1298 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001299 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001300 return a && b;
1301 } else { /* LYS_IFF_OR */
1302 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001303 }
1304 }
1305
Radek Krejciaf566332017-02-07 15:56:59 +01001306 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001307}
1308
1309int
1310resolve_iffeature(struct lys_iffeature *expr)
1311{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001312 int index_e = 0, index_f = 0;
1313
Michal Vaskobdb596d2019-04-29 08:59:30 +02001314 if (expr->expr && expr->features[0]) {
Radek Krejciaf566332017-02-07 15:56:59 +01001315 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 }
Radek Krejciaf566332017-02-07 15:56:59 +01001317 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001318}
1319
1320struct iff_stack {
1321 int size;
1322 int index; /* first empty item */
1323 uint8_t *stack;
1324};
1325
1326static int
1327iff_stack_push(struct iff_stack *stack, uint8_t value)
1328{
1329 if (stack->index == stack->size) {
1330 stack->size += 4;
1331 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001332 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001333 }
1334
1335 stack->stack[stack->index++] = value;
1336 return EXIT_SUCCESS;
1337}
1338
1339static uint8_t
1340iff_stack_pop(struct iff_stack *stack)
1341{
1342 stack->index--;
1343 return stack->stack[stack->index];
1344}
1345
1346static void
1347iff_stack_clean(struct iff_stack *stack)
1348{
1349 stack->size = 0;
1350 free(stack->stack);
1351}
1352
1353static void
1354iff_setop(uint8_t *list, uint8_t op, int pos)
1355{
1356 uint8_t *item;
1357 uint8_t mask = 3;
1358
1359 assert(pos >= 0);
1360 assert(op <= 3); /* max 2 bits */
1361
1362 item = &list[pos / 4];
1363 mask = mask << 2 * (pos % 4);
1364 *item = (*item) & ~mask;
1365 *item = (*item) | (op << 2 * (pos % 4));
1366}
1367
1368uint8_t
1369iff_getop(uint8_t *list, int pos)
1370{
1371 uint8_t *item;
1372 uint8_t mask = 3, result;
1373
1374 assert(pos >= 0);
1375
1376 item = &list[pos / 4];
1377 result = (*item) & (mask << 2 * (pos % 4));
1378 return result >> 2 * (pos % 4);
1379}
1380
1381#define LYS_IFF_LP 0x04 /* ( */
1382#define LYS_IFF_RP 0x08 /* ) */
1383
Radek Krejcicbb473e2016-09-16 14:48:32 +02001384/* internal structure for passing data for UNRES_IFFEAT */
1385struct unres_iffeat_data {
1386 struct lys_node *node;
1387 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001388 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001389};
1390
Radek Krejci9ff0a922016-07-14 13:08:05 +02001391void
1392resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1393{
1394 unsigned int e = 0, f = 0, r = 0;
1395 uint8_t op;
1396
1397 assert(iffeat);
1398
1399 if (!iffeat->expr) {
1400 goto result;
1401 }
1402
1403 do {
1404 op = iff_getop(iffeat->expr, e++);
1405 switch (op) {
1406 case LYS_IFF_NOT:
1407 if (!r) {
1408 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001409 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001410 break;
1411 case LYS_IFF_AND:
1412 case LYS_IFF_OR:
1413 if (!r) {
1414 r += 2;
1415 } else {
1416 r += 1;
1417 }
1418 break;
1419 case LYS_IFF_F:
1420 f++;
1421 if (r) {
1422 r--;
1423 }
1424 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001425 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001426 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001427
Radek Krejci9ff0a922016-07-14 13:08:05 +02001428result:
1429 if (expr_size) {
1430 *expr_size = e;
1431 }
1432 if (feat_size) {
1433 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001434 }
1435}
1436
1437int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001438resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001439 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001440{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001441 const char *c = value;
1442 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001443 int i, j, last_not, checkversion = 0;
1444 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001445 uint8_t op;
1446 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001447 struct unres_iffeat_data *iff_data;
Michal Vasko53b7da02018-02-13 15:28:42 +01001448 struct ly_ctx *ctx = node->module->ctx;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001449
Radek Krejci9ff0a922016-07-14 13:08:05 +02001450 assert(c);
1451
1452 if (isspace(c[0])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001453 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001454 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001455 }
1456
Radek Krejci9ff0a922016-07-14 13:08:05 +02001457 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1458 for (i = j = last_not = 0; c[i]; i++) {
1459 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001460 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001461 j++;
1462 continue;
1463 } else if (c[i] == ')') {
1464 j--;
1465 continue;
1466 } else if (isspace(c[i])) {
1467 continue;
1468 }
1469
1470 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1471 if (c[i + r] == '\0') {
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 } else if (!isspace(c[i + r])) {
1475 /* feature name starting with the not/and/or */
1476 last_not = 0;
1477 f_size++;
1478 } else if (c[i] == 'n') { /* not operation */
1479 if (last_not) {
1480 /* double not */
1481 expr_size = expr_size - 2;
1482 last_not = 0;
1483 } else {
1484 last_not = 1;
1485 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001486 } else { /* and, or */
1487 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488 /* not a not operation */
1489 last_not = 0;
1490 }
1491 i += r;
1492 } else {
1493 f_size++;
1494 last_not = 0;
1495 }
1496 expr_size++;
1497
1498 while (!isspace(c[i])) {
Michal Vaskod9a83662019-03-14 09:47:11 +01001499 if (c[i] == '(') {
1500 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1501 return EXIT_FAILURE;
1502 } else if (!c[i] || c[i] == ')') {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001503 i--;
1504 break;
1505 }
1506 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001507 }
1508 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001509 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001510 /* not matching count of ( and ) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001511 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001512 return EXIT_FAILURE;
1513 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001514
Radek Krejci69b8d922016-07-27 13:13:41 +02001515 if (checkversion || expr_size > 1) {
1516 /* check that we have 1.1 module */
Radek Krejci13fde922018-05-16 10:45:58 +02001517 if (node->module->version != LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001518 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1519 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 +02001520 return EXIT_FAILURE;
1521 }
1522 }
1523
Radek Krejci9ff0a922016-07-14 13:08:05 +02001524 /* allocate the memory */
1525 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001526 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001527 stack.stack = malloc(expr_size * sizeof *stack.stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001528 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001529 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001530 f_size--; expr_size--; /* used as indexes from now */
1531
1532 for (i--; i >= 0; i--) {
1533 if (c[i] == ')') {
1534 /* push it on stack */
1535 iff_stack_push(&stack, LYS_IFF_RP);
1536 continue;
1537 } else if (c[i] == '(') {
1538 /* pop from the stack into result all operators until ) */
1539 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1540 iff_setop(iffeat_expr->expr, op, expr_size--);
1541 }
1542 continue;
1543 } else if (isspace(c[i])) {
1544 continue;
1545 }
1546
1547 /* end operator or operand -> find beginning and get what is it */
1548 j = i + 1;
1549 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1550 i--;
1551 }
1552 i++; /* get back by one step */
1553
Michal Vasko88011352018-07-12 08:49:07 +02001554 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001555 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1556 /* double not */
1557 iff_stack_pop(&stack);
1558 } else {
1559 /* not has the highest priority, so do not pop from the stack
1560 * as in case of AND and OR */
1561 iff_stack_push(&stack, LYS_IFF_NOT);
1562 }
Michal Vasko88011352018-07-12 08:49:07 +02001563 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001564 /* as for OR - pop from the stack all operators with the same or higher
1565 * priority and store them to the result, then push the AND to the stack */
1566 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1567 op = iff_stack_pop(&stack);
1568 iff_setop(iffeat_expr->expr, op, expr_size--);
1569 }
1570 iff_stack_push(&stack, LYS_IFF_AND);
Michal Vasko88011352018-07-12 08:49:07 +02001571 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001572 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1573 op = iff_stack_pop(&stack);
1574 iff_setop(iffeat_expr->expr, op, expr_size--);
1575 }
1576 iff_stack_push(&stack, LYS_IFF_OR);
1577 } else {
1578 /* feature name, length is j - i */
1579
1580 /* add it to the result */
1581 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1582
1583 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001584 * forward referenced, we have to keep the feature name in auxiliary
1585 * structure passed into unres */
1586 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01001587 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001588 iff_data->node = node;
1589 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001590 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001591 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1592 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001593 f_size--;
1594
1595 if (r == -1) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01001596 lydict_remove(node->module->ctx, iff_data->fname);
Pavol Vican4d084512016-09-29 16:38:12 +02001597 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001598 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001599 }
1600 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001601 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001602 while (stack.index) {
1603 op = iff_stack_pop(&stack);
1604 iff_setop(iffeat_expr->expr, op, expr_size--);
1605 }
1606
1607 if (++expr_size || ++f_size) {
1608 /* not all expected operators and operands found */
Michal Vasko53b7da02018-02-13 15:28:42 +01001609 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001610 rc = EXIT_FAILURE;
1611 } else {
1612 rc = EXIT_SUCCESS;
1613 }
1614
1615error:
1616 /* cleanup */
1617 iff_stack_clean(&stack);
1618
1619 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001620}
1621
1622/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001623 * @brief Resolve (find) a data node based on a schema-nodeid.
1624 *
1625 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1626 * module).
1627 *
1628 */
1629struct lyd_node *
1630resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1631{
1632 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001633 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001634 const struct lys_node *schema = NULL;
1635
1636 assert(nodeid && start);
1637
1638 if (nodeid[0] == '/') {
1639 return NULL;
1640 }
1641
1642 str = p = strdup(nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01001643 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001644
Michal Vasko3edeaf72016-02-11 13:17:43 +01001645 while (p) {
1646 token = p;
1647 p = strchr(p, '/');
1648 if (p) {
1649 *p = '\0';
1650 p++;
1651 }
1652
Radek Krejci5da4eb62016-04-08 14:45:51 +02001653 if (p) {
1654 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001655 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001656 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001657 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001658 result = NULL;
1659 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001660 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001661
Radek Krejci5da4eb62016-04-08 14:45:51 +02001662 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1663 continue;
1664 }
1665 } else {
1666 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001667 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001668 || !schema) {
1669 result = NULL;
1670 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001671 }
1672 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001673 LY_TREE_FOR(result ? result->child : start, iter) {
1674 if (iter->schema == schema) {
1675 /* move in data tree according to returned schema */
1676 result = iter;
1677 break;
1678 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001679 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001680 if (!iter) {
1681 /* instance not found */
1682 result = NULL;
1683 break;
1684 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001685 }
1686 free(str);
1687
1688 return result;
1689}
1690
Radek Krejci1a9c3612017-04-24 14:49:43 +02001691int
Michal Vasko50576712017-07-28 12:28:33 +02001692schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1693 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001694{
1695 const struct lys_module *prefix_mod;
1696
Michal Vaskocdb3f062018-02-01 09:55:06 +01001697 /* handle special names */
1698 if (name[0] == '*') {
1699 return 2;
1700 } else if (name[0] == '.') {
1701 return 3;
1702 }
1703
Michal Vasko50576712017-07-28 12:28:33 +02001704 /* name check */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001705 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02001706 return 1;
1707 }
1708
Radek Krejcibdf92362016-04-08 14:43:34 +02001709 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001710 if (mod_name) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001711 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vasko50576712017-07-28 12:28:33 +02001712 if (!prefix_mod) {
1713 return -1;
1714 }
1715 } else {
1716 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001717 }
1718 if (prefix_mod != lys_node_module(sibling)) {
1719 return 1;
1720 }
1721
Michal Vasko50576712017-07-28 12:28:33 +02001722 /* match */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001723 return 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001724}
1725
Michal Vasko50576712017-07-28 12:28:33 +02001726/* keys do not have to be ordered and do not have to be all of them */
1727static int
1728resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1729 const struct lys_module *cur_module, int *nodeid_end)
1730{
1731 int mod_len, nam_len, has_predicate, r, i;
1732 const char *model, *name;
1733 struct lys_node_list *list;
1734
1735 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1736 return 1;
1737 }
1738
1739 list = (struct lys_node_list *)node;
1740 do {
1741 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1742 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001743 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001744 return -1;
1745 }
1746 nodeid += r;
1747
1748 if (node->nodetype == LYS_LEAFLIST) {
1749 /* just check syntax */
1750 if (model || !name || (name[0] != '.') || has_predicate) {
1751 return 1;
1752 }
1753 break;
1754 } else {
1755 /* check the key */
1756 for (i = 0; i < list->keys_size; ++i) {
1757 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1758 continue;
1759 }
1760 if (model) {
1761 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1762 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1763 continue;
1764 }
1765 } else {
1766 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1767 continue;
1768 }
1769 }
1770
1771 /* match */
1772 break;
1773 }
1774
1775 if (i == list->keys_size) {
1776 return 1;
1777 }
1778 }
1779 } while (has_predicate);
1780
1781 if (!nodeid[0]) {
1782 *nodeid_end = 1;
1783 }
1784 return 0;
1785}
1786
Michal Vasko97234262018-02-01 09:53:01 +01001787/* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001788 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001789int
Michal Vasko97234262018-02-01 09:53:01 +01001790resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
Michal Vasko50576712017-07-28 12:28:33 +02001791 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001792{
PavolVicanb28bbff2018-02-21 00:44:02 +01001793 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vasko97234262018-02-01 09:53:01 +01001794 const struct lys_node *sibling, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001795 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001796 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
PavolVicanb28bbff2018-02-21 00:44:02 +01001797 int yang_data_name_len, backup_mod_name_len = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001798 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidaa547a2017-09-22 15:56:27 +02001799 const struct lys_module *start_mod, *aux_mod = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02001800 char *str;
Michal Vasko53b7da02018-02-13 15:28:42 +01001801 struct ly_ctx *ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001802
Michal Vasko97234262018-02-01 09:53:01 +01001803 assert(nodeid && (start_parent || cur_module) && ret);
Michal Vasko50576712017-07-28 12:28:33 +02001804 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001805
Michal Vasko50576712017-07-28 12:28:33 +02001806 if (!cur_module) {
Michal Vasko97234262018-02-01 09:53:01 +01001807 cur_module = lys_node_module(start_parent);
Michal Vasko50576712017-07-28 12:28:33 +02001808 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001809 ctx = cur_module->ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001810 id = nodeid;
1811
PavolVican195cf392018-02-23 13:24:45 +01001812 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
PavolVicanb28bbff2018-02-21 00:44:02 +01001813 if (r < 1) {
Radek Krejci29e85282019-06-10 09:11:10 +02001814 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
PavolVicanb28bbff2018-02-21 00:44:02 +01001815 return -1;
1816 }
1817
1818 if (name[0] == '#') {
1819 if (is_relative) {
1820 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1821 return -1;
1822 }
1823 yang_data_name = name + 1;
1824 yang_data_name_len = nam_len - 1;
1825 backup_mod_name = mod_name;
1826 backup_mod_name_len = mod_name_len;
1827 id += r;
1828 } else {
1829 is_relative = -1;
1830 }
1831
Michal Vasko50576712017-07-28 12:28:33 +02001832 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1833 (extended ? &all_desc : NULL), extended);
1834 if (r < 1) {
Radek Krejci29e85282019-06-10 09:11:10 +02001835 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko50576712017-07-28 12:28:33 +02001836 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001837 }
1838 id += r;
1839
PavolVicanb28bbff2018-02-21 00:44:02 +01001840 if (backup_mod_name) {
1841 mod_name = backup_mod_name;
1842 mod_name_len = backup_mod_name_len;
1843 }
1844
Michal Vasko97234262018-02-01 09:53:01 +01001845 if (is_relative && !start_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001846 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
Michal Vasko3edeaf72016-02-11 13:17:43 +01001847 return -1;
1848 }
1849
1850 /* descendant-schema-nodeid */
1851 if (is_relative) {
Michal Vasko97234262018-02-01 09:53:01 +01001852 cur_module = start_mod = lys_node_module(start_parent);
Michal Vasko24476fa2017-03-08 12:33:48 +01001853
Michal Vasko3edeaf72016-02-11 13:17:43 +01001854 /* absolute-schema-nodeid */
1855 } else {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001856 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01001857 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001858 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001859 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001860 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001861 return -1;
1862 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001863 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01001864 if (yang_data_name) {
1865 start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1866 if (!start_parent) {
1867 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1868 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1869 free(str);
1870 return -1;
1871 }
1872 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001873 }
1874
1875 while (1) {
1876 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001877 last_aug = NULL;
1878
1879 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001880 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1881 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001882 /* we are getting into another module (augment) */
Michal Vasko921eb6b2017-10-13 10:01:39 +02001883 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskobb520442017-05-23 10:55:18 +02001884 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001885 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001886 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001887 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001888 return -1;
1889 }
1890 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001891 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001892 * because this module may be not implemented and it augments something in another module and
1893 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001894 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001895 }
1896
Michal Vasko3b2ad462018-07-10 15:40:53 +02001897 /* look into augments */
1898 if (!extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001899get_next_augment:
1900 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1901 }
1902 }
1903
1904 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vaskocb45f472018-02-12 10:47:42 +01001905 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02001906 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1907
1908 /* resolve predicate */
1909 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1910 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1911 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001912 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001913 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001914 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001915 }
Michal Vasko50576712017-07-28 12:28:33 +02001916 } else if (!id[0]) {
1917 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001918 }
Michal Vasko50576712017-07-28 12:28:33 +02001919
1920 if (r == 0) {
1921 /* one matching result */
1922 if (nodeid_end) {
1923 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001924 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001925 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1926 } else {
1927 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1928 return -1;
1929 }
1930 start_parent = sibling;
1931 }
1932 break;
1933 } else if (r == 1) {
1934 continue;
1935 } else if (r == 2) {
1936 /* "*" */
1937 if (!*ret) {
1938 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001939 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02001940 }
1941 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1942 if (all_desc) {
1943 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1944 if (elem != sibling) {
1945 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1946 }
1947
1948 LY_TREE_DFS_END(sibling, next, elem);
1949 }
1950 }
1951 } else if (r == 3) {
1952 /* "." */
1953 if (!*ret) {
1954 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01001955 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko8b3a2752019-05-17 15:32:44 +02001956 if (start_parent) {
1957 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1958 }
Michal Vasko50576712017-07-28 12:28:33 +02001959 }
1960 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1961 if (all_desc) {
1962 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1963 if (elem != sibling) {
1964 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1965 }
1966
1967 LY_TREE_DFS_END(sibling, next, elem);
1968 }
1969 }
1970 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01001971 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001972 return -1;
1973 }
1974 }
1975
1976 /* skip predicate */
1977 if (extended && has_predicate) {
1978 while (id[0] == '[') {
1979 id = strchr(id, ']');
1980 if (!id) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001981 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02001982 return -1;
1983 }
1984 ++id;
1985 }
1986 }
1987
1988 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1989 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001990 }
1991
1992 /* no match */
1993 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001994 if (last_aug) {
1995 /* it still could be in another augment */
1996 goto get_next_augment;
1997 }
Michal Vasko50576712017-07-28 12:28:33 +02001998 if (no_node_error) {
1999 str = strndup(nodeid, (name - nodeid) + nam_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01002000 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02002001 free(str);
2002 return -1;
2003 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01002004 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002005 return EXIT_SUCCESS;
2006 }
2007
Michal Vasko50576712017-07-28 12:28:33 +02002008 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
2009 (extended ? &all_desc : NULL), extended);
2010 if (r < 1) {
Radek Krejci29e85282019-06-10 09:11:10 +02002011 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko50576712017-07-28 12:28:33 +02002012 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002013 }
2014 id += r;
2015 }
2016
2017 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002018 LOGINT(ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002019 return -1;
2020}
2021
Radek Krejcif3c71de2016-04-11 12:45:46 +02002022/* unique, refine,
2023 * >0 - unexpected char on position (ret - 1),
2024 * 0 - ok (but ret can still be NULL),
2025 * -1 - error,
2026 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002027int
2028resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02002029 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002030{
2031 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002032 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002033 int r, nam_len, mod_name_len, is_relative = -1;
2034 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02002035 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002036
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002037 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01002038 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01002039
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002040 if (!start) {
2041 /* leaf not found */
2042 return 0;
2043 }
2044
Michal Vasko3edeaf72016-02-11 13:17:43 +01002045 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02002046 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002047
Michal Vasko50576712017-07-28 12:28:33 +02002048 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 +01002049 return ((id - nodeid) - r) + 1;
2050 }
2051 id += r;
2052
2053 if (!is_relative) {
2054 return -1;
2055 }
2056
Michal Vasko24476fa2017-03-08 12:33:48 +01002057 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02002058 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01002059 start_parent = lys_parent(start_parent);
2060 }
2061
Michal Vasko3edeaf72016-02-11 13:17:43 +01002062 while (1) {
2063 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002064 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko3223a012020-03-11 08:46:10 +01002065 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES
2066 | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002067 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2068 if (r == 0) {
2069 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002070 if (!(sibling->nodetype & ret_nodetype)) {
2071 /* wrong node type, too bad */
2072 continue;
2073 }
2074 *ret = sibling;
2075 return EXIT_SUCCESS;
2076 }
Michal Vasko50576712017-07-28 12:28:33 +02002077 start_parent = sibling;
2078 break;
2079 } else if (r == 1) {
2080 continue;
2081 } else {
2082 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002083 }
2084 }
2085
2086 /* no match */
2087 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002088 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002089 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02002090 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2091 *ret = NULL;
2092 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002093 }
2094
Michal Vasko50576712017-07-28 12:28:33 +02002095 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 +01002096 return ((id - nodeid) - r) + 1;
2097 }
2098 id += r;
2099 }
2100
2101 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002102 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002103 return -1;
2104}
2105
2106/* choice default */
2107int
2108resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2109{
2110 /* cannot actually be a path */
2111 if (strchr(nodeid, '/')) {
2112 return -1;
2113 }
2114
Michal Vaskodc300b02017-04-07 14:09:20 +02002115 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002116}
2117
2118/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2119static int
2120resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2121{
2122 const struct lys_module *module;
2123 const char *mod_prefix, *name;
2124 int i, mod_prefix_len, nam_len;
2125
2126 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002127 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 +01002128 return -i + 1;
2129 }
2130
Michal Vasko921eb6b2017-10-13 10:01:39 +02002131 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002132 if (!module) {
2133 return -1;
2134 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002135 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002136 start = module->data;
2137 }
2138
2139 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2140
2141 return EXIT_SUCCESS;
2142}
2143
2144int
2145resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2146 const struct lys_node **ret)
2147{
2148 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002149 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002150 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002151 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002152
2153 assert(nodeid && module && ret);
2154 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2155
2156 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002157 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002158
Michal Vasko50576712017-07-28 12:28:33 +02002159 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 +01002160 return ((id - nodeid) - r) + 1;
2161 }
2162 id += r;
2163
2164 if (is_relative) {
2165 return -1;
2166 }
2167
Michal Vasko921eb6b2017-10-13 10:01:39 +02002168 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01002169 if (!abs_start_mod) {
2170 return -1;
2171 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002172
2173 while (1) {
2174 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002175 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vaskocb45f472018-02-12 10:47:42 +01002176 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002177 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2178 if (r == 0) {
2179 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002180 if (!(sibling->nodetype & ret_nodetype)) {
2181 /* wrong node type, too bad */
2182 continue;
2183 }
2184 *ret = sibling;
2185 return EXIT_SUCCESS;
2186 }
Michal Vasko50576712017-07-28 12:28:33 +02002187 start_parent = sibling;
2188 break;
2189 } else if (r == 1) {
2190 continue;
2191 } else {
2192 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002193 }
2194 }
2195
2196 /* no match */
2197 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002198 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002199 return EXIT_SUCCESS;
2200 }
2201
Michal Vasko50576712017-07-28 12:28:33 +02002202 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 +01002203 return ((id - nodeid) - r) + 1;
2204 }
2205 id += r;
2206 }
2207
2208 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002209 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002210 return -1;
2211}
2212
Michal Vaskoe733d682016-03-14 09:08:27 +01002213static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002214resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002215{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002216 const char *mod_name, *name;
2217 int mod_name_len, nam_len, has_predicate, i;
2218 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002219
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002220 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 +02002221 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002222 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002223 return -1;
2224 }
2225
2226 predicate += i;
2227 *parsed += i;
2228
Michal Vasko58c2aab2017-01-05 10:02:05 +01002229 if (!isdigit(name[0])) {
2230 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002231 key = (struct lys_node *)list->keys[i];
2232 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002233 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002234 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002235 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002236
Michal Vasko58c2aab2017-01-05 10:02:05 +01002237 if (i == list->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002238 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko58c2aab2017-01-05 10:02:05 +01002239 return -1;
2240 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002241 }
2242
2243 /* more predicates? */
2244 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002245 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002246 }
2247
2248 return 0;
2249}
2250
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002251/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002252const struct lys_node *
Michal Vasko15b13082019-05-09 10:22:46 +02002253resolve_json_nodeid(const char *nodeid, const struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002254{
Michal Vasko53b7da02018-02-13 15:28:42 +01002255 char *str;
PavolVicanb28bbff2018-02-21 00:44:02 +01002256 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vaskob3744402017-08-03 14:23:58 +02002257 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002258 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
PavolVicanb28bbff2018-02-21 00:44:02 +01002259 int yang_data_name_len, backup_mod_name_len;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002260 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002261 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002262
Michal Vasko3547c532016-03-14 09:40:50 +01002263 assert(nodeid && (ctx || start));
2264 if (!ctx) {
2265 ctx = start->module->ctx;
2266 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002267
2268 id = nodeid;
2269
PavolVican195cf392018-02-23 13:24:45 +01002270 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 +01002271 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2272 return NULL;
2273 }
2274
2275 if (name[0] == '#') {
2276 if (is_relative) {
2277 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2278 return NULL;
2279 }
2280 yang_data_name = name + 1;
2281 yang_data_name_len = nam_len - 1;
2282 backup_mod_name = mod_name;
2283 backup_mod_name_len = mod_name_len;
2284 id += r;
2285 } else {
2286 is_relative = -1;
2287 }
2288
Michal Vasko50576712017-07-28 12:28:33 +02002289 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 +01002290 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002291 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002292 }
2293 id += r;
2294
PavolVicanb28bbff2018-02-21 00:44:02 +01002295 if (backup_mod_name) {
2296 mod_name = backup_mod_name;
2297 mod_name_len = backup_mod_name_len;
2298 }
2299
Michal Vasko3edeaf72016-02-11 13:17:43 +01002300 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002301 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002302 start_parent = start;
2303 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2304 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002305 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002306 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002307 } else {
2308 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002309 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002310 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
Michal Vasko10728b52016-04-07 14:26:29 +02002311 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002312 return NULL;
2313 }
2314
Michal Vasko53b7da02018-02-13 15:28:42 +01002315 str = strndup(mod_name, mod_name_len);
2316 module = ly_ctx_get_module(ctx, str, NULL, 1);
2317 free(str);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002318
Michal Vaskof68a49e2017-08-14 13:23:37 +02002319 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002320 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002321 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002322 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002323 return NULL;
2324 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002325 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01002326 if (yang_data_name) {
2327 start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2328 if (!start_parent) {
2329 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2330 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2331 free(str);
2332 return NULL;
2333 }
2334 }
Michal Vasko3547c532016-03-14 09:40:50 +01002335
2336 /* now it's as if there was no module name */
2337 mod_name = NULL;
2338 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002339 }
2340
Michal Vaskof68a49e2017-08-14 13:23:37 +02002341 prev_mod = module;
2342
Michal Vasko3edeaf72016-02-11 13:17:43 +01002343 while (1) {
2344 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002345 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002346 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002347 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002348 /* output check */
2349 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2350 if (parent) {
2351 if (output && (parent->nodetype == LYS_INPUT)) {
2352 continue;
2353 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2354 continue;
2355 }
2356 }
2357
Michal Vasko3edeaf72016-02-11 13:17:43 +01002358 /* module check */
2359 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002360 /* will also find an augment module */
Michal Vasko53b7da02018-02-13 15:28:42 +01002361 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002362
Michal Vasko3edeaf72016-02-11 13:17:43 +01002363 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002364 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002365 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002366 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002367 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002368 }
2369 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002370 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002371 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002372 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002373 continue;
2374 }
2375
Michal Vaskoe733d682016-03-14 09:08:27 +01002376 /* do we have some predicates on it? */
2377 if (has_predicate) {
2378 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002379 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002380 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002381 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002382 return NULL;
2383 }
2384 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002385 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002386 return NULL;
2387 }
2388 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002389 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002390 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002391 }
2392 id += r;
2393 }
2394
Michal Vasko3edeaf72016-02-11 13:17:43 +01002395 /* the result node? */
2396 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002397 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002398 }
2399
Michal Vaskodc300b02017-04-07 14:09:20 +02002400 /* move down the tree, if possible */
2401 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002402 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskodc300b02017-04-07 14:09:20 +02002403 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002404 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002405 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002406
2407 /* update prev mod */
2408 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002409 break;
2410 }
2411 }
2412
2413 /* no match */
2414 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002415 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002416 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002417 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002418 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002419 }
2420
Michal Vasko50576712017-07-28 12:28:33 +02002421 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 +01002422 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002423 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002424 }
2425 id += r;
2426 }
2427
2428 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002429 LOGINT(ctx);
Michal Vaskoe733d682016-03-14 09:08:27 +01002430 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002431}
2432
Michal Vasko22448d32016-03-16 13:17:29 +01002433static int
Michal Vasko2d44ee02018-05-18 09:38:51 +02002434resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
Michal Vasko22448d32016-03-16 13:17:29 +01002435{
Michal Vasko22448d32016-03-16 13:17:29 +01002436 uint16_t i;
Michal Vaskod51dd422019-04-23 11:51:32 +02002437 char *val_str;
Michal Vaskof29903d2016-04-18 13:13:10 +02002438 struct lyd_node_leaf_list *key;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002439 struct lys_node_list *slist;
Michal Vasko53b7da02018-02-13 15:28:42 +01002440 struct ly_ctx *ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002441
Radek Krejci61a86c62016-03-24 11:06:44 +01002442 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002443 assert(node->schema->nodetype == LYS_LIST);
Michal Vasko2d44ee02018-05-18 09:38:51 +02002444 assert(pp.len);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002445
Michal Vasko53b7da02018-02-13 15:28:42 +01002446 ctx = node->schema->module->ctx;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002447 slist = (struct lys_node_list *)node->schema;
Michal Vasko22448d32016-03-16 13:17:29 +01002448
Michal Vasko53adfc72017-01-06 10:39:10 +01002449 /* is the predicate a number? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002450 if (isdigit(pp.pred[0].name[0])) {
2451 if (position == atoi(pp.pred[0].name)) {
Michal Vasko53adfc72017-01-06 10:39:10 +01002452 /* match */
Michal Vasko53adfc72017-01-06 10:39:10 +01002453 return 0;
2454 } else {
2455 /* not a match */
2456 return 1;
2457 }
2458 }
2459
Michal Vaskof29903d2016-04-18 13:13:10 +02002460 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002461 if (!key) {
2462 /* it is not a position, so we need a key for it to be a match */
2463 return 1;
2464 }
2465
2466 /* go through all the keys */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002467 for (i = 0; i < slist->keys_size; ++i) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002468 if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
2469 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002470 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002471 }
2472
Michal Vasko2d44ee02018-05-18 09:38:51 +02002473 if (pp.pred[i].mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002474 /* specific module, check that the found key is from that module */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002475 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
2476 || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
2477 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002478 return -1;
2479 }
Michal Vasko50576712017-07-28 12:28:33 +02002480
2481 /* but if the module is the same as the parent, it should have been omitted */
2482 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002483 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko50576712017-07-28 12:28:33 +02002484 return -1;
2485 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002486 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002487 /* no module, so it must be the same as the list (parent) */
2488 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002489 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002490 return -1;
2491 }
2492 }
2493
Michal Vaskod51dd422019-04-23 11:51:32 +02002494 /* get canonical value */
2495 val_str = lyd_make_canonical(key->schema, pp.pred[i].value, pp.pred[i].val_len);
2496 if (!val_str) {
2497 return -1;
2498 }
2499
Michal Vasko22448d32016-03-16 13:17:29 +01002500 /* value does not match */
Michal Vaskod51dd422019-04-23 11:51:32 +02002501 if (strcmp(key->value_str, val_str)) {
2502 free(val_str);
Michal Vasko22448d32016-03-16 13:17:29 +01002503 return 1;
2504 }
Michal Vaskod51dd422019-04-23 11:51:32 +02002505 free(val_str);
Michal Vaskof29903d2016-04-18 13:13:10 +02002506
2507 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002508 }
2509
Michal Vasko22448d32016-03-16 13:17:29 +01002510 return 0;
2511}
2512
Radek Krejci45826012016-08-24 15:07:57 +02002513/**
2514 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2515 *
2516 * @param[in] nodeid Node data path to find
2517 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2518 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2519 * @param[out] parsed Number of characters processed in \p id
2520 * @return The closes parent (or the node itself) from the path
2521 */
Michal Vasko22448d32016-03-16 13:17:29 +01002522struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002523resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2524 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002525{
Michal Vasko2d44ee02018-05-18 09:38:51 +02002526 const char *id, *mod_name, *name, *data_val, *llval;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002527 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002528 int has_predicate, last_parsed = 0, llval_len;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002529 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002530 struct lyd_node_leaf_list *llist;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002531 const struct lys_module *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002532 struct ly_ctx *ctx;
Michal Vasko20964782018-08-01 15:14:30 +02002533 const struct lys_node *ssibling, *sparent;
Michal Vasko310bc582018-05-22 10:47:59 +02002534 struct lys_node_list *slist;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002535 struct parsed_pred pp;
Michal Vasko22448d32016-03-16 13:17:29 +01002536
2537 assert(nodeid && start && parsed);
2538
Michal Vasko2d44ee02018-05-18 09:38:51 +02002539 memset(&pp, 0, sizeof pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002540 ctx = start->schema->module->ctx;
2541 id = nodeid;
2542
Michal Vasko2d44ee02018-05-18 09:38:51 +02002543 /* parse first nodeid in case it is yang-data extension */
PavolVican195cf392018-02-23 13:24:45 +01002544 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 +01002545 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002546 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002547 }
2548
2549 if (name[0] == '#') {
2550 if (is_relative) {
2551 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002552 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002553 }
PavolVicanb28bbff2018-02-21 00:44:02 +01002554 id += r;
2555 last_parsed = r;
2556 } else {
2557 is_relative = -1;
2558 }
2559
Michal Vasko2d44ee02018-05-18 09:38:51 +02002560 /* parse first nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002561 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 +01002562 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002563 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002564 }
2565 id += r;
2566 /* add it to parsed only after the data node was actually found */
PavolVicanb28bbff2018-02-21 00:44:02 +01002567 last_parsed += r;
Michal Vasko22448d32016-03-16 13:17:29 +01002568
2569 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002570 prev_mod = lyd_node_module(start);
Michal Vaskoc93bc2d2019-02-08 10:37:46 +01002571 start = (start->schema->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_RPC | LYS_ACTION | LYS_NOTIF)) ? start->child : NULL;
Michal Vasko22448d32016-03-16 13:17:29 +01002572 } else {
2573 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002574 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002575 }
Michal Vaskoc93bc2d2019-02-08 10:37:46 +01002576 if (!start) {
2577 /* there are no siblings to search */
2578 return NULL;
2579 }
Michal Vasko22448d32016-03-16 13:17:29 +01002580
Michal Vaskofebd13d2018-05-17 10:42:24 +02002581 /* do not duplicate code, use predicate parsing from the loop */
2582 goto parse_predicates;
2583
Michal Vasko22448d32016-03-16 13:17:29 +01002584 while (1) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002585 /* find the correct schema node first */
2586 ssibling = NULL;
Michal Vasko20964782018-08-01 15:14:30 +02002587 sparent = (start && start->parent) ? start->parent->schema : NULL;
2588 while ((ssibling = lys_getnext(ssibling, sparent, prev_mod, 0))) {
2589 /* skip invalid input/output nodes */
2590 if (sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
2591 if (options & LYD_PATH_OPT_OUTPUT) {
2592 if (lys_parent(ssibling)->nodetype == LYS_INPUT) {
2593 continue;
2594 }
2595 } else {
2596 if (lys_parent(ssibling)->nodetype == LYS_OUTPUT) {
2597 continue;
2598 }
2599 }
2600 }
2601
Michal Vasko2d44ee02018-05-18 09:38:51 +02002602 if (!schema_nodeid_siblingcheck(ssibling, prev_mod, mod_name, mod_name_len, name, nam_len)) {
2603 break;
Michal Vasko2411b942016-03-23 13:50:03 +01002604 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002605 }
2606 if (!ssibling) {
2607 /* there is not even such a schema node */
2608 free(pp.pred);
2609 return last_match;
2610 }
2611 pp.schema = ssibling;
Michal Vasko2411b942016-03-23 13:50:03 +01002612
Michal Vasko2d44ee02018-05-18 09:38:51 +02002613 /* unify leaf-list value - it is possible to specify last-node value as both a predicate or parameter if
2614 * is a leaf-list, unify both cases and the value will in both cases be in the predicate structure */
2615 if (!id[0] && !pp.len && (ssibling->nodetype == LYS_LEAFLIST)) {
2616 pp.len = 1;
2617 pp.pred = calloc(1, sizeof *pp.pred);
2618 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
Michal Vasko22448d32016-03-16 13:17:29 +01002619
Michal Vasko2d44ee02018-05-18 09:38:51 +02002620 pp.pred[0].name = ".";
2621 pp.pred[0].nam_len = 1;
2622 pp.pred[0].value = (llist_value ? llist_value : "");
2623 pp.pred[0].val_len = strlen(pp.pred[0].value);
2624 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002625
Michal Vasko310bc582018-05-22 10:47:59 +02002626 if (ssibling->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
2627 /* check leaf/leaf-list predicate */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002628 if (pp.len > 1) {
2629 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2630 goto error;
Michal Vasko310bc582018-05-22 10:47:59 +02002631 } else if (pp.len) {
2632 if ((pp.pred[0].name[0] != '.') || (pp.pred[0].nam_len != 1)) {
2633 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp.pred[0].name[0], pp.pred[0].name);
2634 goto error;
2635 }
2636 if ((((struct lys_node_leaf *)ssibling)->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[0].value, ':', pp.pred[0].val_len)) {
2637 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, ssibling, pp.pred[0].val_len, pp.pred[0].value);
2638 goto error;
2639 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002640 }
2641 } else if (ssibling->nodetype == LYS_LIST) {
Michal Vasko310bc582018-05-22 10:47:59 +02002642 /* list should have predicates for all the keys or position */
2643 slist = (struct lys_node_list *)ssibling;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002644 if (!pp.len) {
2645 /* none match */
2646 return last_match;
Michal Vasko310bc582018-05-22 10:47:59 +02002647 } else if (!isdigit(pp.pred[0].name[0])) {
2648 /* list predicate is not a position, so there must be all the keys */
2649 if (pp.len > slist->keys_size) {
2650 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2651 goto error;
2652 } else if (pp.len < slist->keys_size) {
2653 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp.len]->name);
2654 goto error;
2655 }
2656 /* check that all identityrefs have module name, otherwise the hash of the list instance will never match!! */
2657 for (r = 0; r < pp.len; ++r) {
2658 if ((slist->keys[r]->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[r].value, ':', pp.pred[r].val_len)) {
2659 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, slist->keys[r], pp.pred[r].val_len, pp.pred[r].value);
2660 goto error;
2661 }
2662 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002663 }
2664 } else if (pp.pred) {
2665 /* no other nodes allow predicates */
2666 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2667 goto error;
2668 }
2669
Michal Vaskoc340b3d2020-06-29 10:47:11 +02002670 /* we will not be matching list position, keyless lists, or state leaf-lists this way */
2671 if (((pp.schema->nodetype != LYS_LIST) || (((struct lys_node_list *)pp.schema)->keys_size && !isdigit(pp.pred[0].name[0])))
Michal Vasko2d44ee02018-05-18 09:38:51 +02002672 && ((pp.schema->nodetype != LYS_LEAFLIST) || (pp.schema->flags & LYS_CONFIG_W))) {
Michal Vaskoc340b3d2020-06-29 10:47:11 +02002673 sibling = resolve_json_data_node_hash(start, pp);
2674 } else {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002675 list_instance_position = 0;
2676 LY_TREE_FOR(start, sibling) {
2677 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
2678 if (lys_parent(sibling->schema)) {
2679 if (options & LYD_PATH_OPT_OUTPUT) {
2680 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
2681 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
2682 goto error;
2683 }
2684 } else {
2685 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
2686 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
2687 goto error;
2688 }
Michal Vasko22448d32016-03-16 13:17:29 +01002689 }
Michal Vasko22448d32016-03-16 13:17:29 +01002690 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002691
2692 if (sibling->schema != ssibling) {
2693 /* wrong schema node */
Michal Vasko22448d32016-03-16 13:17:29 +01002694 continue;
2695 }
2696
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002697 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002698 if (ssibling->nodetype == LYS_LEAFLIST) {
2699 if (ssibling->flags & LYS_CONFIG_R) {
Michal Vasko24affa02018-04-03 09:06:06 +02002700 /* state leaf-lists will never match */
2701 continue;
2702 }
2703
Michal Vasko9ba34de2016-12-07 12:21:19 +01002704 llist = (struct lyd_node_leaf_list *)sibling;
2705
Michal Vasko2d44ee02018-05-18 09:38:51 +02002706 /* get the expected leaf-list value */
2707 llval = NULL;
2708 llval_len = 0;
2709 if (pp.pred) {
2710 /* it was already checked that it is correct */
2711 llval = pp.pred[0].value;
2712 llval_len = pp.pred[0].val_len;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002713
Michal Vaskof0a50972016-10-19 11:33:55 +02002714 }
2715
Michal Vasko21b90ce2017-09-19 09:38:27 +02002716 /* make value canonical (remove module name prefix) unless it was specified with it */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002717 if (llval && !strchr(llval, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002718 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2719 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002720 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2721 } else {
2722 data_val = llist->value_str;
2723 }
2724
Michal Vasko2d44ee02018-05-18 09:38:51 +02002725 if ((!llval && data_val && data_val[0]) || (llval && (strncmp(llval, data_val, llval_len)
2726 || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002727 continue;
2728 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002729
Michal Vasko2d44ee02018-05-18 09:38:51 +02002730 } else if (ssibling->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002731 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
Michal Vasko58c2aab2017-01-05 10:02:05 +01002732 ++list_instance_position;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002733 ret = resolve_partial_json_data_list_predicate(pp, sibling, list_instance_position);
Michal Vasko22448d32016-03-16 13:17:29 +01002734 if (ret == -1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002735 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002736 } else if (ret == 1) {
2737 /* this list instance does not match */
2738 continue;
2739 }
Michal Vasko22448d32016-03-16 13:17:29 +01002740 }
2741
Michal Vasko22448d32016-03-16 13:17:29 +01002742 break;
2743 }
2744 }
2745
2746 /* no match, return last match */
2747 if (!sibling) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002748 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002749 return last_match;
2750 }
2751
Michal Vasko2d44ee02018-05-18 09:38:51 +02002752 /* we found a next matching node */
2753 *parsed += last_parsed;
Michal Vasko586831d2018-05-22 11:13:16 +02002754 last_match = sibling;
2755 prev_mod = lyd_node_module(sibling);
Michal Vasko2d44ee02018-05-18 09:38:51 +02002756
2757 /* the result node? */
2758 if (!id[0]) {
2759 free(pp.pred);
Michal Vasko586831d2018-05-22 11:13:16 +02002760 return last_match;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002761 }
2762
Michal Vasko586831d2018-05-22 11:13:16 +02002763 /* move down the tree, if possible, and continue */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002764 if (ssibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko586831d2018-05-22 11:13:16 +02002765 /* there can be no children even through expected, error */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002766 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2767 goto error;
Michal Vasko586831d2018-05-22 11:13:16 +02002768 } else if (!sibling->child) {
2769 /* there could be some children, but are not, return what we found so far */
2770 free(pp.pred);
2771 return last_match;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002772 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002773 start = sibling->child;
2774
Michal Vaskofebd13d2018-05-17 10:42:24 +02002775 /* parse nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002776 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 +01002777 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002778 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002779 }
2780 id += r;
2781 last_parsed = r;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002782
2783parse_predicates:
2784 /* parse all the predicates */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002785 free(pp.pred);
2786 pp.schema = NULL;
Michal Vaskoc340b3d2020-06-29 10:47:11 +02002787 pp.pred_str = NULL;
2788 pp.pred_str_len = 0;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002789 pp.len = 0;
2790 pp.pred = NULL;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002791 while (has_predicate) {
Michal Vaskoc340b3d2020-06-29 10:47:11 +02002792 if (!pp.pred_str) {
2793 pp.pred_str = id;
2794 }
2795
Michal Vasko2d44ee02018-05-18 09:38:51 +02002796 ++pp.len;
2797 pp.pred = ly_realloc(pp.pred, pp.len * sizeof *pp.pred);
2798 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2799 if ((r = parse_schema_json_predicate(id, &pp.pred[pp.len - 1].mod_name, &pp.pred[pp.len - 1].mod_name_len,
2800 &pp.pred[pp.len - 1].name, &pp.pred[pp.len - 1].nam_len, &pp.pred[pp.len - 1].value,
2801 &pp.pred[pp.len - 1].val_len, &has_predicate)) < 1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002802 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2803 goto error;
2804 }
2805
2806 id += r;
2807 last_parsed += r;
Michal Vaskoc340b3d2020-06-29 10:47:11 +02002808 pp.pred_str_len += r;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002809 }
Michal Vasko22448d32016-03-16 13:17:29 +01002810 }
2811
Michal Vaskofebd13d2018-05-17 10:42:24 +02002812error:
Michal Vasko238bd2f2016-03-23 09:39:01 +01002813 *parsed = -1;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002814 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002815 return NULL;
2816}
2817
Michal Vasko3edeaf72016-02-11 13:17:43 +01002818/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002819 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002820 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002821 *
Michal Vasko53b7da02018-02-13 15:28:42 +01002822 * @param[in] ctx Context for errors.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 * @param[in] str_restr Restriction as a string.
2824 * @param[in] type Type of the restriction.
2825 * @param[out] ret Final interval structure that starts with
2826 * the interval of the initial type, continues with intervals
2827 * of any superior types derived from the initial one, and
2828 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002829 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002830 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002831 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002832int
Michal Vasko53b7da02018-02-13 15:28:42 +01002833resolve_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 +02002834{
2835 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002836 int kind;
Michal Vaskof75b2772018-03-14 09:55:33 +01002837 int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2838 uint64_t local_umin, local_umax = 0;
2839 uint8_t local_fdig = 0;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002840 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002841 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002842
2843 switch (type->base) {
2844 case LY_TYPE_BINARY:
2845 kind = 0;
2846 local_umin = 0;
2847 local_umax = 18446744073709551615UL;
2848
2849 if (!str_restr && type->info.binary.length) {
2850 str_restr = type->info.binary.length->expr;
2851 }
2852 break;
2853 case LY_TYPE_DEC64:
2854 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002855 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2856 local_fmax = __INT64_C(9223372036854775807);
2857 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002858
2859 if (!str_restr && type->info.dec64.range) {
2860 str_restr = type->info.dec64.range->expr;
2861 }
2862 break;
2863 case LY_TYPE_INT8:
2864 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002865 local_smin = __INT64_C(-128);
2866 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002867
2868 if (!str_restr && type->info.num.range) {
2869 str_restr = type->info.num.range->expr;
2870 }
2871 break;
2872 case LY_TYPE_INT16:
2873 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002874 local_smin = __INT64_C(-32768);
2875 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002876
2877 if (!str_restr && type->info.num.range) {
2878 str_restr = type->info.num.range->expr;
2879 }
2880 break;
2881 case LY_TYPE_INT32:
2882 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002883 local_smin = __INT64_C(-2147483648);
2884 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002885
2886 if (!str_restr && type->info.num.range) {
2887 str_restr = type->info.num.range->expr;
2888 }
2889 break;
2890 case LY_TYPE_INT64:
2891 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002892 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2893 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002894
2895 if (!str_restr && type->info.num.range) {
2896 str_restr = type->info.num.range->expr;
2897 }
2898 break;
2899 case LY_TYPE_UINT8:
2900 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002901 local_umin = __UINT64_C(0);
2902 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002903
2904 if (!str_restr && type->info.num.range) {
2905 str_restr = type->info.num.range->expr;
2906 }
2907 break;
2908 case LY_TYPE_UINT16:
2909 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002910 local_umin = __UINT64_C(0);
2911 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002912
2913 if (!str_restr && type->info.num.range) {
2914 str_restr = type->info.num.range->expr;
2915 }
2916 break;
2917 case LY_TYPE_UINT32:
2918 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002919 local_umin = __UINT64_C(0);
2920 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002921
2922 if (!str_restr && type->info.num.range) {
2923 str_restr = type->info.num.range->expr;
2924 }
2925 break;
2926 case LY_TYPE_UINT64:
2927 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002928 local_umin = __UINT64_C(0);
2929 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002930
2931 if (!str_restr && type->info.num.range) {
2932 str_restr = type->info.num.range->expr;
2933 }
2934 break;
2935 case LY_TYPE_STRING:
2936 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002937 local_umin = __UINT64_C(0);
2938 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002939
2940 if (!str_restr && type->info.str.length) {
2941 str_restr = type->info.str.length->expr;
2942 }
2943 break;
2944 default:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002945 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002946 }
2947
2948 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002949 if (type->der) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002950 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002951 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002952 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002953 assert(!intv || (intv->kind == kind));
2954 }
2955
2956 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002957 /* we do not have any restriction, return superior ones */
2958 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002959 return EXIT_SUCCESS;
2960 }
2961
2962 /* adjust local min and max */
2963 if (intv) {
2964 tmp_intv = intv;
2965
2966 if (kind == 0) {
2967 local_umin = tmp_intv->value.uval.min;
2968 } else if (kind == 1) {
2969 local_smin = tmp_intv->value.sval.min;
2970 } else if (kind == 2) {
2971 local_fmin = tmp_intv->value.fval.min;
2972 }
2973
2974 while (tmp_intv->next) {
2975 tmp_intv = tmp_intv->next;
2976 }
2977
2978 if (kind == 0) {
2979 local_umax = tmp_intv->value.uval.max;
2980 } else if (kind == 1) {
2981 local_smax = tmp_intv->value.sval.max;
2982 } else if (kind == 2) {
2983 local_fmax = tmp_intv->value.fval.max;
2984 }
2985 }
2986
2987 /* finally parse our restriction */
2988 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002989 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002990 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002991 if (!tmp_local_intv) {
2992 assert(!local_intv);
2993 local_intv = malloc(sizeof *local_intv);
2994 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002995 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002996 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002997 tmp_local_intv = tmp_local_intv->next;
2998 }
Michal Vasko53b7da02018-02-13 15:28:42 +01002999 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003000
3001 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003002 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003003 tmp_local_intv->next = NULL;
3004
3005 /* min */
3006 ptr = seg_ptr;
3007 while (isspace(ptr[0])) {
3008 ++ptr;
3009 }
3010 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3011 if (kind == 0) {
Michal Vasko05d83132019-04-02 15:50:40 +02003012 tmp_local_intv->value.uval.min = strtoull(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003013 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003014 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003015 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003016 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003017 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003018 goto error;
3019 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003020 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003021 } else if (!strncmp(ptr, "min", 3)) {
3022 if (kind == 0) {
3023 tmp_local_intv->value.uval.min = local_umin;
3024 } else if (kind == 1) {
3025 tmp_local_intv->value.sval.min = local_smin;
3026 } else if (kind == 2) {
3027 tmp_local_intv->value.fval.min = local_fmin;
3028 }
3029
3030 ptr += 3;
3031 } else if (!strncmp(ptr, "max", 3)) {
3032 if (kind == 0) {
3033 tmp_local_intv->value.uval.min = local_umax;
3034 } else if (kind == 1) {
3035 tmp_local_intv->value.sval.min = local_smax;
3036 } else if (kind == 2) {
3037 tmp_local_intv->value.fval.min = local_fmax;
3038 }
3039
3040 ptr += 3;
3041 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003042 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003043 }
3044
3045 while (isspace(ptr[0])) {
3046 ptr++;
3047 }
3048
3049 /* no interval or interval */
3050 if ((ptr[0] == '|') || !ptr[0]) {
3051 if (kind == 0) {
3052 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
3053 } else if (kind == 1) {
3054 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
3055 } else if (kind == 2) {
3056 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
3057 }
3058 } else if (!strncmp(ptr, "..", 2)) {
3059 /* skip ".." */
3060 ptr += 2;
3061 while (isspace(ptr[0])) {
3062 ++ptr;
3063 }
3064
3065 /* max */
3066 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3067 if (kind == 0) {
Michal Vasko05d83132019-04-02 15:50:40 +02003068 tmp_local_intv->value.uval.max = strtoull(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003069 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003070 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003071 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003072 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003073 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003074 goto error;
3075 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003076 }
3077 } else if (!strncmp(ptr, "max", 3)) {
3078 if (kind == 0) {
3079 tmp_local_intv->value.uval.max = local_umax;
3080 } else if (kind == 1) {
3081 tmp_local_intv->value.sval.max = local_smax;
3082 } else if (kind == 2) {
3083 tmp_local_intv->value.fval.max = local_fmax;
3084 }
3085 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003086 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003087 }
3088 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003089 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003090 }
3091
Michal Vasko05d83132019-04-02 15:50:40 +02003092 /* check min and max in correct order */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003093 if (kind == 0) {
3094 /* current segment */
3095 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
3096 goto error;
3097 }
3098 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
3099 goto error;
3100 }
3101 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02003102 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003103 goto error;
3104 }
3105 } else if (kind == 1) {
3106 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3107 goto error;
3108 }
3109 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3110 goto error;
3111 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003112 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003113 goto error;
3114 }
3115 } else if (kind == 2) {
3116 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3117 goto error;
3118 }
3119 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3120 goto error;
3121 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003122 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003123 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003124 goto error;
3125 }
3126 }
3127
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003128 /* next segment (next OR) */
3129 seg_ptr = strchr(seg_ptr, '|');
3130 if (!seg_ptr) {
3131 break;
3132 }
3133 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003134 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003135 }
3136
3137 /* check local restrictions against superior ones */
3138 if (intv) {
3139 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003140 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003141
3142 while (tmp_local_intv && tmp_intv) {
3143 /* reuse local variables */
3144 if (kind == 0) {
3145 local_umin = tmp_local_intv->value.uval.min;
3146 local_umax = tmp_local_intv->value.uval.max;
3147
3148 /* it must be in this interval */
3149 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3150 /* this interval is covered, next one */
3151 if (local_umax <= tmp_intv->value.uval.max) {
3152 tmp_local_intv = tmp_local_intv->next;
3153 continue;
3154 /* ascending order of restrictions -> fail */
3155 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003156 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003157 }
3158 }
3159 } else if (kind == 1) {
3160 local_smin = tmp_local_intv->value.sval.min;
3161 local_smax = tmp_local_intv->value.sval.max;
3162
3163 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3164 if (local_smax <= tmp_intv->value.sval.max) {
3165 tmp_local_intv = tmp_local_intv->next;
3166 continue;
3167 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003168 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003169 }
3170 }
3171 } else if (kind == 2) {
3172 local_fmin = tmp_local_intv->value.fval.min;
3173 local_fmax = tmp_local_intv->value.fval.max;
3174
Michal Vasko4d1f0482016-09-19 14:35:06 +02003175 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003176 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003177 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003178 tmp_local_intv = tmp_local_intv->next;
3179 continue;
3180 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003181 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003182 }
3183 }
3184 }
3185
3186 tmp_intv = tmp_intv->next;
3187 }
3188
3189 /* some interval left uncovered -> fail */
3190 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003191 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003192 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003193 }
3194
Michal Vaskoaeb51802016-04-11 10:58:47 +02003195 /* append the local intervals to all the intervals of the superior types, return it all */
3196 if (intv) {
3197 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3198 tmp_intv->next = local_intv;
3199 } else {
3200 intv = local_intv;
3201 }
3202 *ret = intv;
3203
3204 return EXIT_SUCCESS;
3205
3206error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003207 while (intv) {
3208 tmp_intv = intv->next;
3209 free(intv);
3210 intv = tmp_intv;
3211 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003212 while (local_intv) {
3213 tmp_local_intv = local_intv->next;
3214 free(local_intv);
3215 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003216 }
3217
Michal Vaskoaeb51802016-04-11 10:58:47 +02003218 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003219}
3220
Michal Vasko4e610cc2019-03-08 13:21:27 +01003221static int
3222resolve_superior_type_check(struct lys_type *type)
3223{
3224 uint32_t i;
3225
3226 if (type->base == LY_TYPE_DER) {
3227 /* check that the referenced typedef is resolved */
3228 return EXIT_FAILURE;
3229 } else if (type->base == LY_TYPE_UNION) {
3230 /* check that all union types are resolved */
3231 for (i = 0; i < type->info.uni.count; ++i) {
3232 if (resolve_superior_type_check(&type->info.uni.types[i])) {
3233 return EXIT_FAILURE;
3234 }
3235 }
3236 } else if (type->base == LY_TYPE_LEAFREF) {
3237 /* check there is path in some derived type */
3238 while (!type->info.lref.path) {
3239 assert(type->der);
3240 type = &type->der->type;
3241 }
3242 }
3243
3244 return EXIT_SUCCESS;
3245}
3246
Michal Vasko730dfdf2015-08-11 14:48:05 +02003247/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003248 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3249 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003250 *
3251 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003252 * @param[in] mod_name Typedef name module name.
3253 * @param[in] module Main module.
3254 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003255 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003256 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003257 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003258 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003259int
Michal Vasko1e62a092015-12-01 12:27:20 +01003260resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3261 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003262{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003263 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003264 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003265 int tpdf_size;
3266
Michal Vasko1dca6882015-10-22 14:29:42 +02003267 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003268 /* no prefix, try built-in types */
3269 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003270 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003271 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003272 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003273 }
3274 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003275 }
3276 }
3277 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003278 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003280 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003281 }
3282 }
3283
Michal Vasko1dca6882015-10-22 14:29:42 +02003284 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285 /* search in local typedefs */
3286 while (parent) {
3287 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003288 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003289 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3290 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 break;
3292
Radek Krejci76512572015-08-04 09:47:08 +02003293 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003294 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3295 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003296 break;
3297
Radek Krejci76512572015-08-04 09:47:08 +02003298 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003299 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3300 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003301 break;
3302
Radek Krejci76512572015-08-04 09:47:08 +02003303 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003304 case LYS_ACTION:
3305 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3306 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003307 break;
3308
Radek Krejci76512572015-08-04 09:47:08 +02003309 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003310 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3311 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003312 break;
3313
Radek Krejci76512572015-08-04 09:47:08 +02003314 case LYS_INPUT:
3315 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003316 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3317 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003318 break;
3319
3320 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003321 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003322 continue;
3323 }
3324
3325 for (i = 0; i < tpdf_size; i++) {
Michal Vasko4e610cc2019-03-08 13:21:27 +01003326 if (!strcmp(tpdf[i].name, name)) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003327 match = &tpdf[i];
Michal Vasko4e610cc2019-03-08 13:21:27 +01003328 goto check_typedef;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003329 }
3330 }
3331
Michal Vaskodcf98e62016-05-05 17:53:53 +02003332 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333 }
Radek Krejcic071c542016-01-27 14:57:51 +01003334 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003336 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003337 if (!module) {
3338 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 }
3340 }
3341
3342 /* search in top level typedefs */
3343 for (i = 0; i < module->tpdf_size; i++) {
Michal Vasko4e610cc2019-03-08 13:21:27 +01003344 if (!strcmp(module->tpdf[i].name, name)) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003345 match = &module->tpdf[i];
Michal Vasko4e610cc2019-03-08 13:21:27 +01003346 goto check_typedef;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003347 }
3348 }
3349
3350 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003351 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003352 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Michal Vasko4e610cc2019-03-08 13:21:27 +01003353 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name)) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003354 match = &module->inc[i].submodule->tpdf[j];
Michal Vasko4e610cc2019-03-08 13:21:27 +01003355 goto check_typedef;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 }
3357 }
3358 }
3359
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003360 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003361
Michal Vasko4e610cc2019-03-08 13:21:27 +01003362check_typedef:
3363 if (resolve_superior_type_check(&match->type)) {
3364 return EXIT_FAILURE;
3365 }
3366
Michal Vasko01c6fd22016-05-20 11:43:05 +02003367 if (ret) {
3368 *ret = match;
3369 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003370 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371}
3372
Michal Vasko1dca6882015-10-22 14:29:42 +02003373/**
3374 * @brief Check the default \p value of the \p type. Logs directly.
3375 *
3376 * @param[in] type Type definition to use.
3377 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003378 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003379 *
3380 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3381 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003382static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003383check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384{
Radek Krejcibad2f172016-08-02 11:04:15 +02003385 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003386 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003387 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003388 char *s;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003389 int ret = EXIT_SUCCESS, r;
Michal Vasko53b7da02018-02-13 15:28:42 +01003390 struct ly_ctx *ctx = module->ctx;
Michal Vasko1dca6882015-10-22 14:29:42 +02003391
Radek Krejci51673202016-11-01 17:00:32 +01003392 assert(value);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003393 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003394
Radek Krejcic13db382016-08-16 10:52:42 +02003395 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003396 /* the type was not resolved yet, nothing to do for now */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003397 ret = EXIT_FAILURE;
3398 goto cleanup;
Michal Vaskoaa1b0f32019-12-12 13:03:12 +01003399 } else if (!module->implemented && ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST))) {
3400 /* /instidsidentityrefs are checked when instantiated in data instead of typedef,
3401 * but the value has to be modified to include the prefix */
Radek Krejci9e6af732017-04-27 14:40:25 +02003402 if (*value) {
3403 if (strchr(*value, ':')) {
3404 dflt = transform_schema2json(module, *value);
3405 } else {
3406 /* default prefix of the module where the typedef is defined */
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003407 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3408 LOGMEM(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003409 ret = -1;
3410 goto cleanup;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003411 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003412 dflt = lydict_insert_zc(ctx, s);
Radek Krejci9e6af732017-04-27 14:40:25 +02003413 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003414 lydict_remove(ctx, *value);
Radek Krejci9e6af732017-04-27 14:40:25 +02003415 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003416 dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003417 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003418 goto cleanup;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003419 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3420 /* leafref in typedef cannot be checked */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003421 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003422 }
3423
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003424 dflt = lydict_insert(ctx, *value, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003425 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003426 /* we do not have a new default value, so is there any to check even, in some base type? */
3427 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3428 if (base_tpdf->dflt) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003429 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
Michal Vasko478c4652016-07-21 12:55:01 +02003430 break;
3431 }
3432 }
3433
Radek Krejci51673202016-11-01 17:00:32 +01003434 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003435 /* no default value, nothing to check, all is well */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003436 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003437 }
3438
3439 /* 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)? */
3440 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003441 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003442 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003443 goto cleanup;
Michal Vasko9301fdf2020-03-09 08:58:43 +01003444 } else if ((type->base == LY_TYPE_IDENT) || (type->base == LY_TYPE_INST)) {
3445 /* impossible to check with a non-implemented module */
3446 goto cleanup;
Radek Krejci9e6af732017-04-27 14:40:25 +02003447 } else {
3448 /* check the default value from typedef, but use also the typedef's module
3449 * due to possible searching in imported modules which is expected in
3450 * typedef's module instead of module where the typedef is used */
3451 module = base_tpdf->module;
3452 }
3453 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003454 case LY_TYPE_INST:
3455 case LY_TYPE_LEAFREF:
3456 case LY_TYPE_BOOL:
3457 case LY_TYPE_EMPTY:
3458 /* 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 +01003459 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003460 case LY_TYPE_BITS:
3461 /* the default value must match the restricted list of values, if the type was restricted */
3462 if (type->info.bits.count) {
3463 break;
3464 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003465 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003466 case LY_TYPE_ENUM:
3467 /* the default value must match the restricted list of values, if the type was restricted */
3468 if (type->info.enums.count) {
3469 break;
3470 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003471 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003472 case LY_TYPE_DEC64:
3473 if (type->info.dec64.range) {
3474 break;
3475 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003476 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003477 case LY_TYPE_BINARY:
3478 if (type->info.binary.length) {
3479 break;
3480 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003481 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003482 case LY_TYPE_INT8:
3483 case LY_TYPE_INT16:
3484 case LY_TYPE_INT32:
3485 case LY_TYPE_INT64:
3486 case LY_TYPE_UINT8:
3487 case LY_TYPE_UINT16:
3488 case LY_TYPE_UINT32:
3489 case LY_TYPE_UINT64:
3490 if (type->info.num.range) {
3491 break;
3492 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003493 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003494 case LY_TYPE_STRING:
3495 if (type->info.str.length || type->info.str.patterns) {
3496 break;
3497 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003498 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003499 case LY_TYPE_UNION:
3500 /* way too much trouble learning whether we need to check the default again, so just do it */
3501 break;
3502 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01003503 LOGINT(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003504 ret = -1;
3505 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003506 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003507 } else if (type->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003508 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3509 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003510 ret = -1;
3511 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003512 }
3513
Michal Vasko1dca6882015-10-22 14:29:42 +02003514 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003515 memset(&node, 0, sizeof node);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003516 node.value_str = lydict_insert(ctx, dflt, 0);
Michal Vasko1dca6882015-10-22 14:29:42 +02003517 node.value_type = type->base;
Michal Vasko31a2d322018-01-12 13:36:12 +01003518
3519 if (tpdf) {
3520 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003521 if (!node.schema) {
3522 LOGMEM(ctx);
3523 ret = -1;
3524 goto cleanup;
3525 }
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003526 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003527 if (r == -1) {
3528 LOGMEM(ctx);
3529 ret = -1;
3530 goto cleanup;
3531 }
Michal Vasko31a2d322018-01-12 13:36:12 +01003532 node.schema->module = module;
3533 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3534 } else {
3535 node.schema = (struct lys_node *)type->parent;
3536 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003537
Radek Krejci37b756f2016-01-18 10:15:03 +01003538 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003539 if (!type->info.lref.target) {
3540 ret = EXIT_FAILURE;
Michal Vasko00f28a72018-11-12 11:55:36 +01003541 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Default value \"%s\" cannot be checked in an unresolved leafref.",
3542 dflt);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003543 goto cleanup;
Michal Vasko1dca6882015-10-22 14:29:42 +02003544 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003545 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003546 if (!ret) {
3547 /* adopt possibly changed default value to its canonical form */
3548 if (*value) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003549 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003550 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003551 dflt = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003552 }
3553 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003554 } else {
Michal Vasko0abb1bc2020-02-25 15:47:10 +01003555 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003556 /* possible forward reference */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003557 ret = EXIT_FAILURE;
Radek Krejcibad2f172016-08-02 11:04:15 +02003558 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003559 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003560 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3561 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3562 /* we have refined bits/enums */
Michal Vasko53b7da02018-02-13 15:28:42 +01003563 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
Radek Krejcibad2f172016-08-02 11:04:15 +02003564 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003565 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003566 }
3567 }
Radek Krejci51673202016-11-01 17:00:32 +01003568 } else {
3569 /* success - adopt canonical form from the node into the default value */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003570 if (!ly_strequal(dflt, node.value_str, 1)) {
Radek Krejci51673202016-11-01 17:00:32 +01003571 /* this can happen only if we have non-inherited default value,
3572 * inherited default values are already in canonical form */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003573 assert(ly_strequal(dflt, *value, 1));
3574
3575 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003576 *value = node.value_str;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003577 node.value_str = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003578 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003579 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003580 }
3581
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003582cleanup:
Michal Vaskod3dd15d2019-01-23 14:06:58 +01003583 lyd_free_value(node.value, node.value_type, node.value_flags, type, node.value_str, NULL, NULL, NULL);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003584 lydict_remove(ctx, node.value_str);
3585 if (tpdf && node.schema) {
Michal Vasko31a2d322018-01-12 13:36:12 +01003586 free((char *)node.schema->name);
3587 free(node.schema);
3588 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003589 lydict_remove(ctx, dflt);
Michal Vasko1dca6882015-10-22 14:29:42 +02003590
3591 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003592}
3593
Michal Vasko730dfdf2015-08-11 14:48:05 +02003594/**
3595 * @brief Check a key for mandatory attributes. Logs directly.
3596 *
3597 * @param[in] key The key to check.
3598 * @param[in] flags What flags to check.
3599 * @param[in] list The list of all the keys.
3600 * @param[in] index Index of the key in the key list.
3601 * @param[in] name The name of the keys.
3602 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003603 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003604 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003605 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003606static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003607check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003608{
Radek Krejciadb57612016-02-16 13:34:34 +01003609 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003610 char *dup = NULL;
3611 int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01003612 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003613
3614 /* existence */
3615 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003616 if (name[len] != '\0') {
3617 dup = strdup(name);
Michal Vasko53b7da02018-02-13 15:28:42 +01003618 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003619 dup[len] = '\0';
3620 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003621 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003622 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003623 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003624 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003625 }
3626
3627 /* uniqueness */
3628 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003629 if (key == list->keys[j]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003630 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003631 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003632 }
3633 }
3634
3635 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003636 if (key->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003637 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003638 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003639 }
3640
3641 /* type of the leaf is not built-in empty */
Radek Krejci13fde922018-05-16 10:45:58 +02003642 if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003643 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003644 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003645 }
3646
3647 /* config attribute is the same as of the list */
Michal Vasko627016e2018-10-24 09:25:55 +02003648 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK)
3649 && ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003650 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003651 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003652 }
3653
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003654 /* key is not placed from augment */
3655 if (key->parent->nodetype == LYS_AUGMENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003656 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3657 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003658 return -1;
3659 }
3660
Radek Krejci404acb62019-09-19 14:33:56 +02003661 /* key is not when/if-feature -conditional
3662 * note that j is really assigned in condition to distinguish when and if-feature, it is not supposed to be a comparison */
Radek Krejci3f21ada2016-08-01 13:34:31 +02003663 j = 0;
3664 if (key->when || (key->iffeature_size && (j = 1))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003665 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3666 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003667 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003668 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003669 }
3670
Michal Vasko0b85aa82016-03-07 14:37:43 +01003671 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003672}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003673
3674/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003675 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003676 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003678 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679 *
3680 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3681 */
3682int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003683resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684{
Radek Krejci581ce772015-11-10 17:22:40 +01003685 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003686 const struct lys_node *leaf = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01003687 struct ly_ctx *ctx = parent->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003688
Michal Vaskodc300b02017-04-07 14:09:20 +02003689 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003690 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003691 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003692 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003693 if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003694 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 +02003695 } else if (rc == -2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003696 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003697 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003698 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003699 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003700 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3701 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003702 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003703 }
Radek Krejci581ce772015-11-10 17:22:40 +01003704 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003706 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003707 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3708 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003709 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003710 }
3711
Radek Krejcicf509982015-12-15 09:22:44 +01003712 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003713 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3714 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003715 return -1;
3716 }
3717
Radek Krejcid09d1a52016-08-11 14:05:45 +02003718 /* check that all unique's targets are of the same config type */
3719 if (*trg_type) {
3720 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003721 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3722 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003723 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3724 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3725 return -1;
3726 }
3727 } else {
3728 /* first unique */
3729 if (leaf->flags & LYS_CONFIG_W) {
3730 *trg_type = 1;
3731 } else {
3732 *trg_type = 2;
3733 }
3734 }
3735
Radek Krejcica7efb72016-01-18 13:06:01 +01003736 /* set leaf's unique flag */
3737 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3738
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003739 return EXIT_SUCCESS;
3740
3741error:
3742
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003743 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003744}
3745
Radek Krejci0c0086a2016-03-24 15:20:28 +01003746void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003747unres_data_del(struct unres_data *unres, uint32_t i)
3748{
3749 /* there are items after the one deleted */
3750 if (i+1 < unres->count) {
3751 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003752 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003753
3754 /* deleting the last item */
3755 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003756 free(unres->node);
3757 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003758 }
3759
3760 /* if there are no items after and it is not the last one, just move the counter */
3761 --unres->count;
3762}
3763
Michal Vasko0491ab32015-08-19 14:28:29 +02003764/**
3765 * @brief Resolve (find) a data node from a specific module. Does not log.
3766 *
3767 * @param[in] mod Module to search in.
3768 * @param[in] name Name of the data node.
3769 * @param[in] nam_len Length of the name.
3770 * @param[in] start Data node to start the search from.
3771 * @param[in,out] parents Resolved nodes. If there are some parents,
3772 * they are replaced (!!) with the resolvents.
3773 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003774 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003775 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003776static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003777resolve_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 +02003778{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003779 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003780 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003781 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003782
Michal Vasko23b61ec2015-08-19 11:19:50 +02003783 if (!parents->count) {
3784 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003785 parents->node = malloc(sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003786 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003787 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003788 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003789 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003790 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003791 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003792 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003793 continue;
3794 }
3795 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003796 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003797 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003798 && node->schema->name[nam_len] == '\0') {
3799 /* matching target */
3800 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003801 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003802 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803 flag = 1;
3804 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003805 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003806 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003807 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003808 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003809 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003810 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003811 }
3812 }
3813 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003814
3815 if (!flag) {
3816 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003817 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003818 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003819 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003820 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003821 }
3822
Michal Vasko0491ab32015-08-19 14:28:29 +02003823 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003824}
3825
Michal Vaskoe27516a2016-10-10 17:55:31 +00003826static int
Michal Vasko299aef12018-12-18 13:13:55 +01003827resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_module *local_mod,
3828 const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003829{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003830 const struct lys_node *node;
3831
Michal Vasko299aef12018-12-18 13:13:55 +01003832 if (!op_node) {
3833 /* leafref pointing to a different module */
3834 if (local_mod != lys_node_module(first_node)) {
3835 return 1;
3836 }
3837 } else if (lys_parent(op_node)) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003838 /* inner operation (notif/action) */
3839 if (abs_path) {
3840 return 1;
3841 } else {
Michal Vasko47579802019-09-24 13:56:47 +02003842 /* if first_node parent is not op_node, it is external */
3843 for (node = first_node; node && (node != op_node); node = lys_parent(node));
3844 if (!node) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003845 return 1;
3846 }
3847 }
3848 } else {
3849 /* top-level operation (notif/rpc) */
3850 if (op_node != first_node) {
3851 return 1;
3852 }
3853 }
3854
3855 return 0;
3856}
3857
Michal Vasko730dfdf2015-08-11 14:48:05 +02003858/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003859 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003860 *
Michal Vaskobb211122015-08-19 14:03:11 +02003861 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003862 * @param[in] context_node Predicate context node (where the predicate is placed).
3863 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003864 * @param[in] node_set Set where to add nodes whose parent chain must be implemented.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003865 *
Michal Vasko184521f2015-09-24 13:14:26 +02003866 * @return 0 on forward reference, otherwise the number
3867 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003868 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003869 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003870static int
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003871resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node, struct lys_node *parent,
3872 struct ly_set *node_set)
Michal Vasko1f76a282015-08-04 16:16:53 +02003873{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003874 const struct lys_module *trg_mod;
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003875 const struct lys_node *src_node, *dst_node, *tmp_parent;
3876 struct lys_node_augment *last_aug;
Michal Vasko1f76a282015-08-04 16:16:53 +02003877 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003878 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
Michal Vasko299aef12018-12-18 13:13:55 +01003879 int has_predicate, dest_parent_times, i, rc;
Michal Vasko53b7da02018-02-13 15:28:42 +01003880 struct ly_ctx *ctx = context_node->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003881
3882 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003883 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003884 &pke_len, &has_predicate)) < 1) {
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003885 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path - i);
3886 return -parsed + i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003887 }
3888 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003889 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003890
Michal Vasko58090902015-08-13 14:04:15 +02003891 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003892 if (sour_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003893 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003894 } else {
Michal Vaskoa50e60c2018-08-22 12:07:21 +02003895 trg_mod = lys_node_module(parent);
Michal Vasko36cbaa42015-12-14 13:15:48 +01003896 }
Michal Vasko32fb4992019-03-08 08:55:16 +01003897 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, LYS_GETNEXT_NOSTATECHECK,
3898 &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003899 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003900 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003901 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003902 }
3903
3904 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003905 dest_parent_times = 0;
3906 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003907 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3908 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003909 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003910 return -parsed;
3911 }
3912 pke_parsed += i;
3913
Radek Krejciadb57612016-02-16 13:34:34 +01003914 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskoec06ed42018-12-07 08:33:55 +01003915 if (!dst_node) {
3916 /* we went too much into parents, there is no parent anymore */
3917 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
3918 return 0;
3919 }
3920
Michal Vasko3ba2d792017-07-10 15:14:43 +02003921 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3922 && !((struct lys_node_augment *)dst_node->parent)->target) {
3923 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003924 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003925 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3926 return 0;
3927 }
3928
Michal Vaskofbaead72016-10-07 10:54:48 +02003929 /* path is supposed to be evaluated in data tree, so we have to skip
3930 * all schema nodes that cannot be instantiated in data tree */
3931 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003932 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003933 dst_node = lys_parent(dst_node));
Michal Vasko1f76a282015-08-04 16:16:53 +02003934 }
3935 while (1) {
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003936 last_aug = NULL;
3937
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003938 if (dest_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003939 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003940 } else {
Michal Vaskoa50e60c2018-08-22 12:07:21 +02003941 trg_mod = lys_node_module(parent);
Michal Vasko36cbaa42015-12-14 13:15:48 +01003942 }
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003943
3944 if (!trg_mod->implemented && dst_node) {
3945 get_next_augment:
3946 last_aug = lys_getnext_target_aug(last_aug, trg_mod, dst_node);
3947 }
3948
3949 tmp_parent = (last_aug ? (struct lys_node *)last_aug : dst_node);
3950 rc = lys_getnext_data(trg_mod, tmp_parent, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF,
Michal Vasko32fb4992019-03-08 08:55:16 +01003951 LYS_GETNEXT_NOSTATECHECK, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003952 if (rc) {
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003953 if (last_aug) {
3954 /* restore the correct augment target */
3955 dst_node = last_aug->target;
3956 goto get_next_augment;
3957 }
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003958 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003959 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003960 }
3961
3962 if (pke_len == pke_parsed) {
3963 break;
3964 }
3965
Michal Vaskobb520442017-05-23 10:55:18 +02003966 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 +02003967 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003968 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003969 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed) - i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003970 return -parsed;
3971 }
3972 pke_parsed += i;
3973 }
3974
3975 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003976 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003977 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
Michal Vasko53b7da02018-02-13 15:28:42 +01003978 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003979 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003980 return -parsed;
3981 }
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02003982
3983 /* add both nodes into node set */
3984 ly_set_add(node_set, (void *)dst_node, 0);
3985 ly_set_add(node_set, (void *)src_node, 0);
Michal Vasko1f76a282015-08-04 16:16:53 +02003986 } while (has_predicate);
3987
3988 return parsed;
3989}
3990
Michal Vasko74083ec2018-06-15 10:00:12 +02003991static int
3992check_leafref_features(struct lys_type *type)
3993{
3994 struct lys_node *iter;
3995 struct ly_set *src_parents, *trg_parents, *features;
3996 struct lys_node_augment *aug;
3997 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
3998 unsigned int i, j, size, x;
3999 int ret = EXIT_SUCCESS;
4000
4001 assert(type->parent);
4002
4003 src_parents = ly_set_new();
4004 trg_parents = ly_set_new();
4005 features = ly_set_new();
4006
4007 /* get parents chain of source (leafref) */
4008 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
4009 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4010 continue;
4011 }
4012 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4013 aug = (struct lys_node_augment *)iter->parent;
4014 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4015 /* unresolved augment, wait until it's resolved */
4016 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4017 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4018 ret = EXIT_FAILURE;
4019 goto cleanup;
4020 }
Michal Vaskod42871e2018-07-12 09:06:53 +02004021 /* also add this augment */
4022 ly_set_add(src_parents, aug, LY_SET_OPT_USEASLIST);
Michal Vasko74083ec2018-06-15 10:00:12 +02004023 }
4024 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
4025 }
4026 /* get parents chain of target */
4027 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
4028 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4029 continue;
4030 }
4031 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4032 aug = (struct lys_node_augment *)iter->parent;
4033 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4034 /* unresolved augment, wait until it's resolved */
4035 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4036 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4037 ret = EXIT_FAILURE;
4038 goto cleanup;
4039 }
4040 }
4041 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
4042 }
4043
4044 /* compare the features used in if-feature statements in the rest of both
4045 * chains of parents. The set of features used for target must be a subset
4046 * of features used for the leafref. This is not a perfect, we should compare
4047 * the truth tables but it could require too much resources, so we simplify that */
4048 for (i = 0; i < src_parents->number; i++) {
4049 iter = src_parents->set.s[i]; /* shortcut */
4050 if (!iter->iffeature_size) {
4051 continue;
4052 }
4053 for (j = 0; j < iter->iffeature_size; j++) {
4054 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4055 for (; size; size--) {
4056 if (!iter->iffeature[j].features[size - 1]) {
4057 /* not yet resolved feature, postpone this check */
4058 ret = EXIT_FAILURE;
4059 goto cleanup;
4060 }
4061 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
4062 }
4063 }
4064 }
4065 x = features->number;
4066 for (i = 0; i < trg_parents->number; i++) {
4067 iter = trg_parents->set.s[i]; /* shortcut */
4068 if (!iter->iffeature_size) {
4069 continue;
4070 }
4071 for (j = 0; j < iter->iffeature_size; j++) {
4072 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4073 for (; size; size--) {
4074 if (!iter->iffeature[j].features[size - 1]) {
4075 /* not yet resolved feature, postpone this check */
4076 ret = EXIT_FAILURE;
4077 goto cleanup;
4078 }
4079 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
4080 /* the feature is not present in features set of target's parents chain */
Michal Vasko33672502020-01-09 10:22:52 +01004081 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, type->parent,
Michal Vasko74083ec2018-06-15 10:00:12 +02004082 "Leafref is not conditional based on \"%s\" feature as its target.",
4083 iter->iffeature[j].features[size - 1]->name);
Michal Vasko33672502020-01-09 10:22:52 +01004084 for (iter = type->info.lref.target->parent; iter && (iter->nodetype != LYS_USES); iter = lys_parent(iter));
4085 if (iter) {
4086 /* we are in a uses so there can still be a refine that will add an if-feature */
4087 ret = EXIT_FAILURE;
4088 } else {
4089 ret = -1;
4090 }
Michal Vasko74083ec2018-06-15 10:00:12 +02004091 goto cleanup;
4092 }
4093 }
4094 }
4095 }
4096
4097cleanup:
4098 ly_set_free(features);
4099 ly_set_free(src_parents);
4100 ly_set_free(trg_parents);
4101
4102 return ret;
4103}
4104
Michal Vasko730dfdf2015-08-11 14:48:05 +02004105/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004106 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004107 *
Michal Vaskobb211122015-08-19 14:03:11 +02004108 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004109 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004110 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004111 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004112 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004113 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004114static int
Michal Vasko74083ec2018-06-15 10:00:12 +02004115resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
Michal Vasko1f76a282015-08-04 16:16:53 +02004116{
Michal Vaskocb45f472018-02-12 10:47:42 +01004117 const struct lys_node *node, *op_node = NULL, *tmp_parent;
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004118 struct ly_set *node_set;
Michal Vaskobb520442017-05-23 10:55:18 +02004119 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004120 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02004121 const char *id, *prefix, *name;
4122 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskocb45f472018-02-12 10:47:42 +01004123 int i, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01004124 struct ly_ctx *ctx = parent->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02004125
Michal Vasko9e451f92019-07-19 11:57:53 +02004126 /* first check that we are not in an unresolved augment */
4127 for (node = parent; lys_parent(node); node = lys_parent(node));
4128 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)) {
4129 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
4130 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
4131 return EXIT_FAILURE;
4132 }
4133
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004134 first_iter = 1;
4135 parent_times = 0;
4136 id = type->info.lref.path;
4137 node_set = ly_set_new();
4138 if (!node_set) {
4139 LOGMEM(ctx);
4140 return -1;
4141 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004142
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004143 /* find operation schema we are in */
4144 for (op_node = lys_parent(parent);
4145 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
4146 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02004147
Michal Vasko2a33c212020-05-07 09:08:13 +02004148 if (type->der->module) {
4149 /* typedef, take its local module */
4150 cur_module = type->der->module;
4151 } else {
4152 cur_module = lys_node_module(parent);
4153 }
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004154 do {
4155 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
4156 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
4157 ly_set_free(node_set);
4158 return -1;
4159 }
4160 id += i;
4161
4162 /* get the current module */
4163 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
4164 if (!tmp_mod) {
4165 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4166 ly_set_free(node_set);
4167 return EXIT_FAILURE;
4168 }
4169 last_aug = NULL;
4170
4171 if (first_iter) {
4172 if (parent_times == -1) {
4173 /* use module data */
4174 node = NULL;
4175
4176 } else if (parent_times > 0) {
4177 /* we are looking for the right parent */
4178 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004179 /* path is supposed to be evaluated in data tree, so we have to skip
4180 * all schema nodes that cannot be instantiated in data tree */
4181 for (node = lys_parent(node);
4182 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
4183 node = lys_parent(node));
4184
4185 if (!node) {
4186 if (i == parent_times - 1) {
4187 /* top-level */
4188 break;
4189 }
4190
4191 /* higher than top-level */
4192 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4193 ly_set_free(node_set);
4194 return EXIT_FAILURE;
4195 }
4196 }
4197 } else {
4198 LOGINT(ctx);
4199 ly_set_free(node_set);
4200 return -1;
4201 }
4202 }
4203
4204 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
4205 * - useless to search for that in augments) */
4206 if (!tmp_mod->implemented && node) {
4207 get_next_augment:
4208 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
4209 }
4210
4211 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
4212 node = NULL;
4213 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
4214 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
4215 continue;
4216 }
4217 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
4218 continue;
4219 }
4220 /* match */
4221 break;
4222 }
4223 if (!node) {
4224 if (last_aug) {
4225 /* restore the correct augment target */
4226 node = last_aug->target;
4227 goto get_next_augment;
4228 }
4229 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4230 ly_set_free(node_set);
4231 return EXIT_FAILURE;
4232 }
4233
4234 if (first_iter) {
Michal Vaskoc17f9e12019-09-05 13:29:26 +02004235 /* find module whose data will actually contain this leafref */
4236 for (tmp_parent = parent; lys_parent(tmp_parent); tmp_parent = lys_parent(tmp_parent));
4237
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004238 /* set external dependency flag, we can decide based on the first found node */
Michal Vaskoc17f9e12019-09-05 13:29:26 +02004239 if (resolve_schema_leafref_valid_dep_flag(op_node, lys_node_module(tmp_parent), node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004240 parent->flags |= LYS_LEAFREF_DEP;
4241 }
4242 first_iter = 0;
4243 }
4244
4245 if (has_predicate) {
4246 /* we have predicate, so the current result must be list */
4247 if (node->nodetype != LYS_LIST) {
4248 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4249 ly_set_free(node_set);
4250 return -1;
4251 }
4252
4253 i = resolve_schema_leafref_predicate(id, node, parent, node_set);
4254 if (!i) {
4255 ly_set_free(node_set);
4256 return EXIT_FAILURE;
4257 } else if (i < 0) {
4258 ly_set_free(node_set);
Michal Vaskobb520442017-05-23 10:55:18 +02004259 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004260 }
4261 id += i;
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004262 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004263 }
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004264 } while (id[0]);
Michal Vasko1f76a282015-08-04 16:16:53 +02004265
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004266 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
4267 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
4268 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4269 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
4270 ly_set_free(node_set);
4271 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004272 }
4273
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004274 /* check status */
4275 if (lyp_check_status(parent->flags, parent->module, parent->name,
4276 node->flags, node->module, node->name, node)) {
4277 ly_set_free(node_set);
4278 return -1;
4279 }
4280
4281 /* assign */
4282 type->info.lref.target = (struct lys_node_leaf *)node;
4283
4284 /* add the target node into a set so its parent chain modules can be implemented */
4285 ly_set_add(node_set, (void *)node, 0);
4286
Michal Vasko9e451f92019-07-19 11:57:53 +02004287 /* find the actual module of this leafref, it can be in a foreign augment */
4288 for (node = parent; lys_parent(node); node = lys_parent(node));
4289 if (lys_node_module(node)->implemented) {
Michal Vasko74083ec2018-06-15 10:00:12 +02004290 /* make all the modules in the path implemented */
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004291 for (i = 0; (unsigned)i < node_set->number; ++i) {
4292 for (node = node_set->set.s[i]; node; node = lys_parent(node)) {
4293 if (!lys_node_module(node)->implemented) {
4294 lys_node_module(node)->implemented = 1;
4295 if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4296 ly_set_free(node_set);
4297 return -1;
4298 }
Michal Vasko74083ec2018-06-15 10:00:12 +02004299 }
4300 }
Michal Vasko74083ec2018-06-15 10:00:12 +02004301
Michal Vasko10765502020-01-09 10:22:27 +01004302 /* check leafref that it is allowed */
4303 if (lys_leaf_check_leafref((struct lys_node_leaf *)node_set->set.s[i], (struct lys_node *)type->parent)) {
Michal Vasko113cae52019-10-14 09:28:54 +02004304 ly_set_free(node_set);
4305 return -1;
4306 }
Michal Vasko74083ec2018-06-15 10:00:12 +02004307 }
Radek Krejcicf509982015-12-15 09:22:44 +01004308 }
Michal Vaskoba8fd2b2019-04-25 11:17:36 +02004309 ly_set_free(node_set);
Radek Krejcicf509982015-12-15 09:22:44 +01004310
Michal Vasko74083ec2018-06-15 10:00:12 +02004311 /* check if leafref and its target are under common if-features */
4312 return check_leafref_features(type);
Michal Vasko1f76a282015-08-04 16:16:53 +02004313}
4314
Michal Vasko730dfdf2015-08-11 14:48:05 +02004315/**
Michal Vasko718ecdd2017-10-03 14:12:39 +02004316 * @brief Compare 2 data node values.
4317 *
4318 * Comparison performed on canonical forms, the first value
4319 * is first transformed into canonical form.
4320 *
4321 * @param[in] node Leaf/leaf-list with these values.
4322 * @param[in] noncan_val Non-canonical value.
4323 * @param[in] noncan_val_len Length of \p noncal_val.
4324 * @param[in] can_val Canonical value.
4325 * @return 1 if equal, 0 if not, -1 on error (logged).
4326 */
4327static int
4328valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4329{
4330 int ret;
4331 struct lyd_node_leaf_list leaf;
4332 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4333
4334 /* dummy leaf */
4335 memset(&leaf, 0, sizeof leaf);
4336 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4337
4338repeat:
4339 leaf.value_type = sleaf->type.base;
4340 leaf.schema = node;
4341
4342 if (leaf.value_type == LY_TYPE_LEAFREF) {
4343 if (!sleaf->type.info.lref.target) {
4344 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01004345 LOGINT(node->module->ctx);
Michal Vasko718ecdd2017-10-03 14:12:39 +02004346 ret = -1;
4347 goto finish;
4348 }
4349 sleaf = sleaf->type.info.lref.target;
4350 goto repeat;
4351 } else {
Michal Vasko0abb1bc2020-02-25 15:47:10 +01004352 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
Michal Vasko718ecdd2017-10-03 14:12:39 +02004353 ret = -1;
4354 goto finish;
4355 }
4356 }
4357
4358 if (!strcmp(leaf.value_str, can_val)) {
4359 ret = 1;
4360 } else {
4361 ret = 0;
4362 }
4363
4364finish:
4365 lydict_remove(node->module->ctx, leaf.value_str);
4366 return ret;
4367}
4368
4369/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004370 * @brief Resolve instance-identifier predicate in JSON data format.
4371 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004372 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02004373 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02004374 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004375 * @param[in,out] node Node matching the restriction without
4376 * the predicate. If it does not satisfy the predicate,
4377 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004378 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004379 * @return Number of characters successfully parsed,
4380 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004381 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004382static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004383resolve_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 +02004384{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004385 /* ... /node[key=value] ... */
4386 struct lyd_node_leaf_list *key;
4387 struct lys_node_leaf **list_keys = NULL;
Michal Vaskoab8adcd2017-10-02 13:32:24 +02004388 struct lys_node_list *slist = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004389 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004390 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vasko53b7da02018-02-13 15:28:42 +01004391 struct ly_ctx *ctx = prev_mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004392
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004393 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02004394
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004395 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004396 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004397 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4398 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004399 }
4400 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004401
Michal Vasko88850b72017-10-02 13:13:21 +02004402 if (!(*node)) {
4403 /* just parse it all */
4404 continue;
4405 }
4406
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004407 /* target */
4408 if (name[0] == '.') {
4409 /* leaf-list value */
4410 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004411 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004412 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4413 parsed = -1;
4414 goto cleanup;
4415 }
4416
4417 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004418 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004419 *node = NULL;
4420 goto cleanup;
4421 }
4422
4423 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004424 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004425
4426 /* keyless list position */
4427 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004428 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004429 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4430 parsed = -1;
4431 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004432 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004433
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004434 if (((struct lys_node_list *)(*node)->schema)->keys) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004435 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 +02004436 (*node)->schema->name);
4437 parsed = -1;
4438 goto cleanup;
4439 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004440
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004441 /* check the index */
4442 if (atoi(name) != cur_idx) {
4443 *node = NULL;
4444 goto cleanup;
4445 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004446
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004447 } else {
4448 /* list key value */
4449 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004450 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004451 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4452 parsed = -1;
4453 goto cleanup;
4454 }
4455 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004456
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004457 /* prepare key array */
4458 if (!list_keys) {
4459 list_keys = malloc(slist->keys_size * sizeof *list_keys);
Michal Vasko53b7da02018-02-13 15:28:42 +01004460 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004461 for (i = 0; i < slist->keys_size; ++i) {
4462 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02004463 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004464 }
4465
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004466 /* find the schema key leaf */
4467 for (i = 0; i < slist->keys_size; ++i) {
4468 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4469 break;
4470 }
4471 }
4472 if (i == slist->keys_size) {
4473 /* this list has no such key */
Michal Vasko53b7da02018-02-13 15:28:42 +01004474 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004475 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4476 parsed = -1;
4477 goto cleanup;
4478 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004479
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004480 /* check module */
4481 if (model) {
4482 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004483 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 +02004484 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4485 parsed = -1;
4486 goto cleanup;
4487 }
4488 } else {
4489 if (list_keys[i]->module != prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004490 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 +02004491 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4492 parsed = -1;
4493 goto cleanup;
4494 }
4495 }
4496
4497 /* find the actual data key */
4498 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4499 if (key->schema == (struct lys_node *)list_keys[i]) {
4500 break;
4501 }
4502 }
4503 if (!key) {
4504 /* list instance is missing a key? definitely should not happen */
Michal Vasko53b7da02018-02-13 15:28:42 +01004505 LOGINT(ctx);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004506 parsed = -1;
4507 goto cleanup;
4508 }
4509
4510 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004511 if (!valequal(key->schema, value, val_len, key->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004512 *node = NULL;
Michal Vasko88850b72017-10-02 13:13:21 +02004513 /* we still want to parse the whole predicate */
4514 continue;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004515 }
4516
4517 /* everything is fine, mark this key as resolved */
4518 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004519 }
4520 } while (has_predicate);
4521
Michal Vaskob2f40be2016-09-08 16:03:48 +02004522 /* check that all list keys were specified */
Michal Vasko88850b72017-10-02 13:13:21 +02004523 if (*node && list_keys) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004524 for (i = 0; i < slist->keys_size; ++i) {
4525 if (list_keys[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004526 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 +02004527 parsed = -1;
4528 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004529 }
4530 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004531 }
4532
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004533cleanup:
4534 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004535 return parsed;
4536}
4537
Michal Vasko895c11f2018-03-12 11:35:58 +01004538static int
4539check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004540{
Michal Vasko0b963112017-08-11 12:45:36 +02004541 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004542 struct lyxp_set set;
Michal Vasko895c11f2018-03-12 11:35:58 +01004543 enum int_log_opts prev_ilo;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004544
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004545 if (check_place) {
4546 parent = node;
4547 while (parent) {
4548 if (parent->nodetype == LYS_GROUPING) {
4549 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004550 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004551 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004552 if (parent->nodetype == LYS_AUGMENT) {
4553 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004554 /* unresolved augment, skip for now (will be checked later) */
4555 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004556 } else {
4557 parent = ((struct lys_node_augment *)parent)->target;
4558 continue;
4559 }
4560 }
4561 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004562 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004563 }
4564
Michal Vasko895c11f2018-03-12 11:35:58 +01004565 memset(&set, 0, sizeof set);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004566
Michal Vasko895c11f2018-03-12 11:35:58 +01004567 /* produce just warnings */
4568 ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4569 lyxp_node_atomize(node, &set, 1);
4570 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4571
4572 if (set.val.snodes) {
4573 free(set.val.snodes);
4574 }
4575 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004576}
4577
Radek Krejcif71f48f2016-10-25 16:37:24 +02004578static int
4579check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4580{
Radek Krejcidce5f972017-09-12 15:47:49 +02004581 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004582
4583 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004584 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4585 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004586 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 +02004587 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4588 return -1;
4589 }
4590 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4591 * of leafref resolving (lys_leaf_add_leafref_target()) */
4592 } else if (type->base == LY_TYPE_UNION) {
4593 for (i = 0; i < type->info.uni.count; i++) {
4594 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4595 return -1;
4596 }
4597 }
4598 }
4599 return 0;
4600}
4601
Michal Vasko9e635ac2016-10-17 11:44:09 +02004602/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004603 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004604 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004605 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004606 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004607 * @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 +02004608 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004609 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004610 *
4611 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004612 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004613int
4614inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004615{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004616 struct lys_node_leaf *leaf;
Michal Vasko53b7da02018-02-13 15:28:42 +01004617 struct ly_ctx *ctx;
4618
4619 if (!node) {
4620 return 0;
4621 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004622
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004623 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Michal Vasko53b7da02018-02-13 15:28:42 +01004624 ctx = node->module->ctx;
4625
Radek Krejci1d82ef62015-08-07 14:44:40 +02004626 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004627 if (clear) {
4628 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004629 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004630 } else {
4631 if (node->flags & LYS_CONFIG_SET) {
4632 /* skip nodes with an explicit config value */
4633 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004634 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4635 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004636 return -1;
4637 }
4638 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004639 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004640
4641 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4642 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4643 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004644 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4645 && !((struct lys_node_list *)node)->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004646 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
Michal Vaskoe022a562016-09-27 14:24:15 +02004647 return -1;
4648 }
4649 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004650 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004651 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004652 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004653 return -1;
4654 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004655 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4656 leaf = (struct lys_node_leaf *)node;
4657 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004658 return -1;
4659 }
4660 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004661 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004662
4663 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004664}
4665
Michal Vasko730dfdf2015-08-11 14:48:05 +02004666/**
Michal Vasko7178e692016-02-12 15:58:05 +01004667 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004668 *
Michal Vaskobb211122015-08-19 14:03:11 +02004669 * @param[in] aug Augment to use.
Michal Vasko97234262018-02-01 09:53:01 +01004670 * @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 +01004671 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004672 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004673 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004674 */
Michal Vasko7178e692016-02-12 15:58:05 +01004675static int
Michal Vasko97234262018-02-01 09:53:01 +01004676resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004677{
Michal Vasko44ab1462017-05-18 13:18:36 +02004678 int rc;
Radek Krejci63495df2019-10-10 09:06:27 +02004679 struct lys_node *sub, *next;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004680 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004681 struct ly_set *set;
Michal Vasko53b7da02018-02-13 15:28:42 +01004682 struct ly_ctx *ctx;
Radek Krejci63495df2019-10-10 09:06:27 +02004683 struct lys_node_case *c;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004684
Michal Vasko2ef7db62017-06-12 09:24:02 +02004685 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004686 mod = lys_main_module(aug->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01004687 ctx = mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004688
Michal Vaskobb520442017-05-23 10:55:18 +02004689 /* set it as not applied for now */
4690 aug->flags |= LYS_NOTAPPLIED;
4691
Michal Vasko2ef7db62017-06-12 09:24:02 +02004692 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004693 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004694 /* resolve target node */
Michal Vasko97234262018-02-01 09:53:01 +01004695 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 +02004696 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004697 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004698 return -1;
4699 }
Michal Vasko50576712017-07-28 12:28:33 +02004700 if (!set) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004701 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004702 return EXIT_FAILURE;
4703 }
Michal Vasko50576712017-07-28 12:28:33 +02004704 aug->target = set->set.s[0];
4705 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004706 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004707
Michal Vasko74083ec2018-06-15 10:00:12 +02004708 /* make this module implemented if the target module is (if the target is in an unimplemented module,
4709 * it is fine because when we will be making that module implemented, its augment will be applied
4710 * and that augment target module made implemented, recursively) */
4711 if (mod->implemented && !lys_node_module(aug->target)->implemented) {
4712 lys_node_module(aug->target)->implemented = 1;
4713 if (unres_schema_add_node(lys_node_module(aug->target), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4714 return -1;
4715 }
4716 }
4717
Michal Vaskod58d5962016-03-02 14:29:41 +01004718 /* check for mandatory nodes - if the target node is in another module
4719 * the added nodes cannot be mandatory
4720 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004721 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4722 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004723 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004724 }
4725
Michal Vasko07e89ef2016-03-03 13:28:57 +01004726 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004727 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004728 LY_TREE_FOR(aug->child, sub) {
4729 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4730 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004731 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4732 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004733 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004734 return -1;
4735 }
4736 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004737 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004738 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004739 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004740 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4741 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004742 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004743 return -1;
4744 }
4745 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004746 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004747 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004748 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004749 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4750 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004751 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004752 return -1;
4753 }
4754 }
4755 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004756 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4757 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 +01004758 return -1;
4759 }
4760
Radek Krejcic071c542016-01-27 14:57:51 +01004761 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004762 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004763 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004764 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004765 }
4766 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004767
Radek Krejci63495df2019-10-10 09:06:27 +02004768 if (aug->target->nodetype == LYS_CHOICE) {
4769 /* in the case of implicit cases, we have to create the nodes representing them
4770 * to serve as a target of the augments, they won't be printed, but they are expected in the tree */
4771 LY_TREE_FOR_SAFE(aug->child, next, sub) {
4772 if (sub->nodetype == LYS_CASE) {
4773 /* explicit case */
4774 continue;
4775 }
4776
4777 c = calloc(1, sizeof *c);
4778 LY_CHECK_ERR_RETURN(!c, LOGMEM(ctx), EXIT_FAILURE);
4779 c->name = lydict_insert(ctx, sub->name, 0);
4780 c->flags = LYS_IMPLICIT | (sub->flags & LYS_CONFIG_MASK);
4781 c->module = sub->module;
4782 c->nodetype = LYS_CASE;
4783 c->parent = sub->parent;
4784 c->prev = sub->prev != sub ? sub->prev : (struct lys_node*)c;
4785 if (c->prev->next) {
4786 c->prev->next = (struct lys_node*)c;
4787 } else {
4788 c->parent->child = (struct lys_node*)c;
4789 }
4790 c->next = sub->next;
4791 if (c->next) {
4792 c->next->prev = (struct lys_node*)c;
4793 } else {
4794 c->parent->child->prev = (struct lys_node*)c;
4795 }
4796 c->child = sub;
4797 sub->prev = sub;
4798 sub->next = NULL;
4799 sub->parent = (struct lys_node*)c;
4800 }
4801 }
4802
Michal Vasko8fa6ec22020-03-05 15:29:26 +01004803 LY_TREE_DFS_BEGIN(aug->child, next, sub) {
4804 if (sub->nodetype == LYS_ACTION) {
4805 /* we need to check parents */
4806 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4807 if ((sub->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))
4808 || ((sub->nodetype == LYS_LIST) && !((struct lys_node_list *)sub)->keys)) {
4809 LOGVAL(ctx, LYE_INPAR, LY_VLOG_LYS, aug->target, strnodetype(sub->nodetype), "action");
4810 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4811 return -1;
4812 }
4813 }
4814 break;
4815 }
4816 LY_TREE_DFS_END(aug->child, next, sub);
4817 }
4818
Michal Vasko44ab1462017-05-18 13:18:36 +02004819 if (!aug->child) {
4820 /* empty augment, nothing to connect, but it is techincally applied */
Michal Vasko53b7da02018-02-13 15:28:42 +01004821 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
Michal Vasko44ab1462017-05-18 13:18:36 +02004822 aug->flags &= ~LYS_NOTAPPLIED;
Radek Krejciaa6b2a12017-10-26 15:52:39 +02004823 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4824 /* we try to connect the augment only in case the module is implemented or
4825 * the augment applies on the used grouping, anyway we failed here */
Michal Vasko44ab1462017-05-18 13:18:36 +02004826 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004827 }
4828
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004829 return EXIT_SUCCESS;
4830}
4831
Radek Krejcie534c132016-11-23 13:32:31 +01004832static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004833resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004834{
4835 enum LY_VLOG_ELEM vlog_type;
4836 void *vlog_node;
4837 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004838 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004839 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004840 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004841 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004842 struct lys_ext_instance *tmp_ext;
Michal Vasko53b7da02018-02-13 15:28:42 +01004843 struct ly_ctx *ctx = NULL;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004844 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004845
4846 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004847 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004848 vlog_node = info->parent;
4849 vlog_type = LY_VLOG_LYS;
4850 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004851 case LYEXT_PAR_MODULE:
4852 case LYEXT_PAR_IMPORT:
4853 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004854 vlog_node = NULL;
4855 vlog_type = LY_VLOG_LYS;
4856 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004857 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004858 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004859 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004860 break;
4861 }
4862
4863 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004864 /* YIN */
4865
Radek Krejcie534c132016-11-23 13:32:31 +01004866 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004867 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004868 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004869 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004870 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004871 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004872 ctx = mod->ctx;
Radek Krejcie534c132016-11-23 13:32:31 +01004873
4874 /* find the extension definition */
4875 e = NULL;
4876 for (i = 0; i < mod->extensions_size; i++) {
4877 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4878 e = &mod->extensions[i];
4879 break;
4880 }
4881 }
4882 /* try submodules */
4883 for (j = 0; !e && j < mod->inc_size; j++) {
4884 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4885 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4886 e = &mod->inc[j].submodule->extensions[i];
4887 break;
4888 }
4889 }
4890 }
4891 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004892 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004893 return EXIT_FAILURE;
4894 }
4895
4896 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004897
Radek Krejci72b35992017-01-04 16:27:44 +01004898 if (e->plugin && e->plugin->check_position) {
4899 /* common part - we have plugin with position checking function, use it first */
4900 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4901 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004902 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004903 return -1;
4904 }
4905 }
4906
Radek Krejci8d6b7422017-02-03 14:42:13 +01004907 /* extension type-specific part - allocation */
4908 if (e->plugin) {
4909 etype = e->plugin->type;
4910 } else {
4911 /* default type */
4912 etype = LYEXT_FLAG;
4913 }
4914 switch (etype) {
4915 case LYEXT_FLAG:
4916 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4917 break;
4918 case LYEXT_COMPLEX:
4919 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4920 break;
4921 case LYEXT_ERR:
4922 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004923 LOGINT(ctx);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004924 return -1;
4925 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004926 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004927
4928 /* common part for all extension types */
4929 (*ext)->def = e;
4930 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004931 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004932 (*ext)->insubstmt = info->substmt;
4933 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004934 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004935 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004936
PavolVicand86b0d62017-09-01 11:01:39 +02004937 if (e->argument) {
4938 if (!(e->flags & LYS_YINELEM)) {
4939 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4940 if (!(*ext)->arg_value) {
PavolVicane7a1fc62018-02-19 16:50:27 +01004941 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
PavolVicand86b0d62017-09-01 11:01:39 +02004942 return -1;
4943 }
4944
4945 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4946 } else {
4947 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4948 if (ly_strequal(yin->name, e->argument, 1)) {
4949 (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
4950 lyxml_free(mod->ctx, yin);
4951 break;
4952 }
4953 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004954 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004955 }
4956
PavolVican92f23622017-12-12 13:35:56 +01004957 if ((*ext)->flags & LYEXT_OPT_VALID &&
4958 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004959 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004960 }
4961
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004962 (*ext)->nodetype = LYS_EXT;
4963 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004964
Radek Krejci8d6b7422017-02-03 14:42:13 +01004965 /* extension type-specific part - parsing content */
4966 switch (etype) {
4967 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004968 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4969 if (!yin->ns) {
4970 /* garbage */
4971 lyxml_free(mod->ctx, yin);
4972 continue;
4973 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4974 /* standard YANG statements are not expected here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004975 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004976 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004977 } else if (yin->ns == info->data.yin->ns &&
4978 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004979 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004980 if ((*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004981 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004982 return -1;
4983 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004984 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004985 yin->content = NULL;
4986 lyxml_free(mod->ctx, yin);
4987 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004988 /* extension instance */
4989 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4990 LYEXT_SUBSTMT_SELF, 0, unres)) {
4991 return -1;
4992 }
Radek Krejci72b35992017-01-04 16:27:44 +01004993
Radek Krejci72b35992017-01-04 16:27:44 +01004994 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004995 }
Radek Krejci72b35992017-01-04 16:27:44 +01004996 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004997 break;
4998 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004999 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01005000 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
5001 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01005002 return -1;
5003 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01005004 break;
5005 default:
5006 break;
Radek Krejcie534c132016-11-23 13:32:31 +01005007 }
Radek Krejci72b35992017-01-04 16:27:44 +01005008
5009 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
5010
Radek Krejcie534c132016-11-23 13:32:31 +01005011 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01005012 /* YANG */
5013
PavolVicanc1807262017-01-31 18:00:27 +01005014 ext_prefix = (char *)(*ext)->def;
5015 tmp = strchr(ext_prefix, ':');
5016 if (!tmp) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005017 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01005018 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01005019 }
5020 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01005021
PavolVicanc1807262017-01-31 18:00:27 +01005022 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005023 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
PavolVicanc1807262017-01-31 18:00:27 +01005024 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005025 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01005026 return EXIT_FAILURE;
5027 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005028 ctx = mod->ctx;
PavolVicanc1807262017-01-31 18:00:27 +01005029
5030 /* find the extension definition */
5031 e = NULL;
5032 for (i = 0; i < mod->extensions_size; i++) {
5033 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
5034 e = &mod->extensions[i];
5035 break;
5036 }
5037 }
5038 /* try submodules */
5039 for (j = 0; !e && j < mod->inc_size; j++) {
5040 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
5041 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
5042 e = &mod->inc[j].submodule->extensions[i];
5043 break;
5044 }
5045 }
5046 }
5047 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005048 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01005049 return EXIT_FAILURE;
5050 }
5051
PavolVicanfcc98762017-09-01 15:51:39 +02005052 (*ext)->flags &= ~LYEXT_OPT_YANG;
5053 (*ext)->def = NULL;
5054
PavolVicanc1807262017-01-31 18:00:27 +01005055 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
5056
5057 if (e->plugin && e->plugin->check_position) {
5058 /* common part - we have plugin with position checking function, use it first */
5059 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
5060 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01005061 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01005062 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01005063 }
5064 }
5065
Michal Vasko3676bfb2019-03-12 08:51:54 +01005066 if (e->argument && !(*ext)->arg_value) {
5067 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
5068 goto error;
5069 }
5070
PavolVican22e88682017-02-14 22:38:18 +01005071 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01005072 (*ext)->def = e;
5073 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01005074 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01005075 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
PavolVican22e88682017-02-14 22:38:18 +01005076
PavolVican92f23622017-12-12 13:35:56 +01005077 if ((*ext)->flags & LYEXT_OPT_VALID &&
5078 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01005079 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
PavolVican92f23622017-12-12 13:35:56 +01005080 }
5081
Radek Krejci7f1d47e2017-04-12 15:29:02 +02005082 (*ext)->module = info->mod;
5083 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02005084
PavolVican22e88682017-02-14 22:38:18 +01005085 /* extension type-specific part */
5086 if (e->plugin) {
5087 etype = e->plugin->type;
5088 } else {
5089 /* default type */
5090 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01005091 }
PavolVican22e88682017-02-14 22:38:18 +01005092 switch (etype) {
5093 case LYEXT_FLAG:
5094 /* nothing change */
5095 break;
5096 case LYEXT_COMPLEX:
Radek Krejcib728c9f2018-12-06 09:42:17 +01005097 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Michal Vasko53b7da02018-02-13 15:28:42 +01005098 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
Radek Krejcib728c9f2018-12-06 09:42:17 +01005099 memset((char *)tmp_ext + offsetof(struct lys_ext_instance_complex, content), 0,
5100 ((struct lyext_plugin_complex*)e->plugin)->instance_size - offsetof(struct lys_ext_instance_complex, content));
PavolVican22e88682017-02-14 22:38:18 +01005101 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01005102 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01005103 if (info->data.yang) {
5104 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01005105 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
5106 (struct lys_ext_instance_complex*)(*ext))) {
5107 goto error;
5108 }
5109 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
5110 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01005111 goto error;
5112 }
PavolVicana3876672017-02-21 15:49:51 +01005113 }
5114 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
5115 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01005116 }
PavolVican22e88682017-02-14 22:38:18 +01005117 break;
5118 case LYEXT_ERR:
5119 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01005120 LOGINT(ctx);
PavolVican22e88682017-02-14 22:38:18 +01005121 goto error;
5122 }
5123
PavolVican22e88682017-02-14 22:38:18 +01005124 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
5125 goto error;
5126 }
5127 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01005128 }
5129
5130 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01005131error:
5132 free(ext_prefix);
5133 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01005134}
5135
Michal Vasko730dfdf2015-08-11 14:48:05 +02005136/**
Pavol Vican855ca622016-09-05 13:07:54 +02005137 * @brief Resolve (find) choice default case. Does not log.
5138 *
5139 * @param[in] choic Choice to use.
5140 * @param[in] dflt Name of the default case.
5141 *
5142 * @return Pointer to the default node or NULL.
5143 */
5144static struct lys_node *
5145resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
5146{
5147 struct lys_node *child, *ret;
5148
5149 LY_TREE_FOR(choic->child, child) {
5150 if (child->nodetype == LYS_USES) {
5151 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
5152 if (ret) {
5153 return ret;
5154 }
5155 }
5156
5157 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02005158 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02005159 return child;
5160 }
5161 }
5162
5163 return NULL;
5164}
5165
5166/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02005167 * @brief Resolve uses, apply augments, refines. Logs directly.
5168 *
Michal Vaskobb211122015-08-19 14:03:11 +02005169 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005170 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005171 *
Michal Vaskodef0db12015-10-07 13:22:48 +02005172 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005173 */
Michal Vasko184521f2015-09-24 13:14:26 +02005174static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005175resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005176{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005177 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02005178 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02005179 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02005180 struct lys_node_leaflist *llist;
5181 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02005182 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005183 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02005184 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005185 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005186 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02005187 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005188
Michal Vasko71e1aa82015-08-12 12:17:51 +02005189 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01005190
Radek Krejci93def382017-05-24 15:33:48 +02005191 /* check that the grouping is resolved (no unresolved uses inside) */
5192 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02005193
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005194 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01005195 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01005196 if (node_aux->nodetype & LYS_GROUPING) {
5197 /* do not instantiate groupings from groupings */
5198 continue;
5199 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01005200 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01005201 if (!node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005202 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
5203 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005204 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005205 }
Pavol Vican55abd332016-07-12 15:54:49 +02005206 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01005207 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 +02005208 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005209 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02005210 }
5211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005212 }
Michal Vaskoe022a562016-09-27 14:24:15 +02005213
Michal Vaskodef0db12015-10-07 13:22:48 +02005214 /* we managed to copy the grouping, the rest must be possible to resolve */
5215
Pavol Vican855ca622016-09-05 13:07:54 +02005216 if (uses->refine_size) {
5217 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Michal Vasko53b7da02018-02-13 15:28:42 +01005218 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005219 }
5220
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005221 /* apply refines */
5222 for (i = 0; i < uses->refine_size; i++) {
5223 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01005224 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
5225 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02005226 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01005227 if (rc || !node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005228 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005229 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005230 }
5231
Radek Krejci1d82ef62015-08-07 14:44:40 +02005232 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005233 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5234 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005235 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005236 }
Pavol Vican855ca622016-09-05 13:07:54 +02005237 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005238
5239 /* description on any nodetype */
5240 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005241 lydict_remove(ctx, node->dsc);
5242 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005243 }
5244
5245 /* reference on any nodetype */
5246 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005247 lydict_remove(ctx, node->ref);
5248 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005249 }
5250
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005251 /* config on any nodetype,
5252 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
5253 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005254 node->flags &= ~LYS_CONFIG_MASK;
5255 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005256 }
5257
5258 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02005259 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005260 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005261 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02005262 leaf = (struct lys_node_leaf *)node;
5263
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005264 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02005265 lydict_remove(ctx, leaf->dflt);
5266 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
5267
5268 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01005269 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
5270 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005271 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005272 }
Radek Krejci200bf712016-08-16 17:11:04 +02005273 } else if (node->nodetype == LYS_LEAFLIST) {
5274 /* leaf-list */
5275 llist = (struct lys_node_leaflist *)node;
5276
5277 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01005278 for (j = 0; j < llist->dflt_size; j++) {
5279 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02005280 }
5281 free(llist->dflt);
5282
5283 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02005284 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
Michal Vasko53b7da02018-02-13 15:28:42 +01005285 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
Radek Krejci200bf712016-08-16 17:11:04 +02005286 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01005287 for (j = 0; j < llist->dflt_size; j++) {
5288 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02005289 }
5290
5291 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01005292 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01005293 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01005294 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02005295 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02005296 }
5297 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005298 }
5299 }
5300
5301 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02005302 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01005303 /* remove current value */
5304 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005305
Radek Krejcibf285832017-01-26 16:05:41 +01005306 /* set new value */
5307 node->flags |= (rfn->flags & LYS_MAND_MASK);
5308
Pavol Vican855ca622016-09-05 13:07:54 +02005309 if (rfn->flags & LYS_MAND_TRUE) {
5310 /* check if node has default value */
5311 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005312 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005313 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005314 goto fail;
5315 }
5316 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005317 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005318 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005319 goto fail;
5320 }
5321 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005322 }
5323
5324 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005325 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
5326 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
5327 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005328 }
5329
5330 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005331 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005332 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005333 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005334 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005335 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005336 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005337 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02005338 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005339 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005340 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005341 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005342 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005343 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005344 }
5345 }
5346
5347 /* must in leaf, leaf-list, list, container or anyxml */
5348 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005349 switch (node->nodetype) {
5350 case LYS_LEAF:
5351 old_size = &((struct lys_node_leaf *)node)->must_size;
5352 old_must = &((struct lys_node_leaf *)node)->must;
5353 break;
5354 case LYS_LEAFLIST:
5355 old_size = &((struct lys_node_leaflist *)node)->must_size;
5356 old_must = &((struct lys_node_leaflist *)node)->must;
5357 break;
5358 case LYS_LIST:
5359 old_size = &((struct lys_node_list *)node)->must_size;
5360 old_must = &((struct lys_node_list *)node)->must;
5361 break;
5362 case LYS_CONTAINER:
5363 old_size = &((struct lys_node_container *)node)->must_size;
5364 old_must = &((struct lys_node_container *)node)->must;
5365 break;
5366 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005367 case LYS_ANYDATA:
5368 old_size = &((struct lys_node_anydata *)node)->must_size;
5369 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005370 break;
5371 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01005372 LOGINT(ctx);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005373 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005374 }
5375
5376 size = *old_size + rfn->must_size;
5377 must = realloc(*old_must, size * sizeof *rfn->must);
Michal Vasko53b7da02018-02-13 15:28:42 +01005378 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005379 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01005380 must[j].ext_size = rfn->must[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005381 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 +02005382 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02005383 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5384 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5385 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5386 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5387 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02005388 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005389 }
5390
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005391 *old_must = must;
5392 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02005393
5394 /* check XPath dependencies again */
5395 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5396 goto fail;
5397 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005398 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02005399
5400 /* if-feature in leaf, leaf-list, list, container or anyxml */
5401 if (rfn->iffeature_size) {
5402 old_size = &node->iffeature_size;
5403 old_iff = &node->iffeature;
5404
5405 size = *old_size + rfn->iffeature_size;
5406 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Michal Vasko53b7da02018-02-13 15:28:42 +01005407 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02005408 *old_iff = iff;
5409
Pavol Vican855ca622016-09-05 13:07:54 +02005410 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5411 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005412 if (usize1) {
5413 /* there is something to duplicate */
5414 /* duplicate compiled expression */
Radek Krejci4e7ea7a2019-12-05 09:46:39 +01005415 usize = (usize1 / 4) + ((usize1 % 4) ? 1 : 0);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005416 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Michal Vasko53b7da02018-02-13 15:28:42 +01005417 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005418 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005419
5420 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005421 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Michal Vasko53b7da02018-02-13 15:28:42 +01005422 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005423 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005424
Radek Krejci3a3b2002017-09-13 16:39:02 +02005425 /* duplicate extensions */
5426 iff[j].ext_size = rfn->iffeature[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005427 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
Radek Krejci3a3b2002017-09-13 16:39:02 +02005428 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5429 }
5430 (*old_size)++;
5431 }
5432 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005433 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005434 }
5435
5436 /* apply augments */
5437 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko97234262018-02-01 09:53:01 +01005438 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005439 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005440 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005441 }
5442 }
5443
Pavol Vican855ca622016-09-05 13:07:54 +02005444 /* check refines */
5445 for (i = 0; i < uses->refine_size; i++) {
5446 node = refine_nodes[i];
5447 rfn = &uses->refine[i];
5448
5449 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005450 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005451 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005452 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005453 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5454 (rfn->flags & LYS_CONFIG_W)) {
5455 /* setting config true under config false is prohibited */
Michal Vasko53b7da02018-02-13 15:28:42 +01005456 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5457 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005458 "changing config from 'false' to 'true' is prohibited while "
5459 "the target's parent is still config 'false'.");
5460 goto fail;
5461 }
5462
5463 /* inherit config change to the target children */
5464 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5465 if (rfn->flags & LYS_CONFIG_W) {
5466 if (iter->flags & LYS_CONFIG_SET) {
5467 /* config is set explicitely, go to next sibling */
5468 next = NULL;
5469 goto nextsibling;
5470 }
5471 } else { /* LYS_CONFIG_R */
5472 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5473 /* error - we would have config data under status data */
Michal Vasko53b7da02018-02-13 15:28:42 +01005474 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5475 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005476 "changing config from 'true' to 'false' is prohibited while the target "
5477 "has still a children with explicit config 'true'.");
5478 goto fail;
5479 }
5480 }
5481 /* change config */
5482 iter->flags &= ~LYS_CONFIG_MASK;
5483 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5484
5485 /* select next iter - modified LY_TREE_DFS_END */
5486 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5487 next = NULL;
5488 } else {
5489 next = iter->child;
5490 }
5491nextsibling:
5492 if (!next) {
5493 /* try siblings */
5494 next = iter->next;
5495 }
5496 while (!next) {
5497 /* parent is already processed, go to its sibling */
5498 iter = lys_parent(iter);
5499
5500 /* no siblings, go back through parents */
5501 if (iter == node) {
5502 /* we are done, no next element to process */
5503 break;
5504 }
5505 next = iter->next;
5506 }
5507 }
5508 }
5509
5510 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005511 if (rfn->dflt_size) {
5512 if (node->nodetype == LYS_CHOICE) {
5513 /* choice */
5514 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5515 rfn->dflt[0]);
5516 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005517 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005518 goto fail;
5519 }
5520 if (lyp_check_mandatory_choice(node)) {
5521 goto fail;
5522 }
Pavol Vican855ca622016-09-05 13:07:54 +02005523 }
5524 }
5525
5526 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005527 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005528 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005529 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5530 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005531 goto fail;
5532 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005533 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005534 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005535 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5536 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005537 goto fail;
5538 }
5539 }
5540
5541 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005542 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005543 if (node->nodetype == LYS_LEAFLIST) {
5544 llist = (struct lys_node_leaflist *)node;
5545 if (llist->dflt_size && llist->min) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005546 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5547 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005548 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5549 goto fail;
5550 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005551 } else if (node->nodetype == LYS_LEAF) {
5552 leaf = (struct lys_node_leaf *)node;
5553 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005554 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5555 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005556 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5557 goto fail;
5558 }
Pavol Vican855ca622016-09-05 13:07:54 +02005559 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005560
Pavol Vican855ca622016-09-05 13:07:54 +02005561 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005562 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005563 for (parent = node->parent;
5564 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5565 parent = parent->parent) {
5566 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5567 /* stop also on presence containers */
5568 break;
5569 }
5570 }
5571 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5572 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5573 if (lyp_check_mandatory_choice(parent)) {
5574 goto fail;
5575 }
5576 }
5577 }
5578 }
5579 free(refine_nodes);
5580
Michal Vasko4d886c42020-05-29 09:31:16 +02005581 /* check list config after all the refines were applied */
5582 LY_TREE_DFS_BEGIN((struct lys_node *)uses, next, iter) {
5583 if ((iter->nodetype == LYS_LIST) && (iter->flags & LYS_CONFIG_W)
5584 && !((struct lys_node_list *)iter)->keys_size) {
5585 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, iter, "key", "list");
5586 goto fail;
5587 }
5588 LY_TREE_DFS_END((struct lys_node *)uses, next, iter);
5589 }
5590
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005591 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005592
5593fail:
5594 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5595 lys_node_free(iter, NULL, 0);
5596 }
Pavol Vican855ca622016-09-05 13:07:54 +02005597 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005598 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005599}
5600
Radek Krejci83a4bac2017-02-07 15:53:04 +01005601void
5602resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005603{
5604 int i;
5605
5606 assert(der && base);
5607
Radek Krejci018f1f52016-08-03 16:01:20 +02005608 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005609 /* create a set for backlinks if it does not exist */
5610 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005611 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005612 /* store backlink */
5613 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005614
Radek Krejci85a54be2016-10-20 12:39:56 +02005615 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005616 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005617 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005618 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005619}
5620
Michal Vasko730dfdf2015-08-11 14:48:05 +02005621/**
5622 * @brief Resolve base identity recursively. Does not log.
5623 *
5624 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005625 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005626 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005627 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005628 *
Radek Krejci219fa612016-08-15 10:36:51 +02005629 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005630 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005631static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005632resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005633 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005634{
Michal Vaskof02e3742015-08-05 16:27:02 +02005635 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005636 struct lys_ident *base = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005637 struct ly_ctx *ctx = module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005638
Radek Krejcicf509982015-12-15 09:22:44 +01005639 assert(ret);
5640
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005641 /* search module */
5642 for (i = 0; i < module->ident_size; i++) {
5643 if (!strcmp(basename, module->ident[i].name)) {
5644
5645 if (!ident) {
5646 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005647 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005648 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005649 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005650 }
5651
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005652 base = &module->ident[i];
5653 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005654 }
5655 }
5656
5657 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005658 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5659 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5660 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005661
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005662 if (!ident) {
5663 *ret = &module->inc[j].submodule->ident[i];
5664 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005665 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005666
5667 base = &module->inc[j].submodule->ident[i];
5668 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005669 }
5670 }
5671 }
5672
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005673matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005674 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005675 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005676 /* is it already completely resolved? */
5677 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005678 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005679 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5680
5681 /* simple check for circular reference,
5682 * the complete check is done as a side effect of using only completely
5683 * resolved identities (previous check of unres content) */
5684 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005685 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5686 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005687 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005688 }
5689
Radek Krejci06f64ed2016-08-15 11:07:44 +02005690 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005691 }
5692 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005693
Radek Krejcibabbff82016-02-19 13:31:37 +01005694 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005695 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005696 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005697 }
5698
Radek Krejci219fa612016-08-15 10:36:51 +02005699 /* base not found (maybe a forward reference) */
5700 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005701}
5702
Michal Vasko730dfdf2015-08-11 14:48:05 +02005703/**
5704 * @brief Resolve base identity. Logs directly.
5705 *
5706 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005707 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005708 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005709 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005710 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005711 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005712 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005713 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005714static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005715resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005716 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005717{
5718 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005719 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005720 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005721 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005722 struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005723 struct ly_ctx *ctx = module->ctx;
Radek Krejcicf509982015-12-15 09:22:44 +01005724
5725 assert((ident && !type) || (!ident && type));
5726
5727 if (!type) {
5728 /* have ident to resolve */
5729 ret = &target;
5730 flags = ident->flags;
5731 mod = ident->module;
5732 } else {
5733 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005734 ++type->info.ident.count;
5735 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 +01005736 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005737
5738 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005739 flags = type->parent->flags;
5740 mod = type->parent->module;
5741 }
Michal Vaskof2006002016-04-21 16:28:15 +02005742 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005743
5744 /* search for the base identity */
5745 name = strchr(basename, ':');
5746 if (name) {
5747 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005748 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005749 name++;
5750
Michal Vasko2d851a92015-10-20 16:16:36 +02005751 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005752 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005753 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005754 }
5755 } else {
5756 name = basename;
5757 }
5758
Radek Krejcic071c542016-01-27 14:57:51 +01005759 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005760 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
Radek Krejcic071c542016-01-27 14:57:51 +01005761 if (!module) {
5762 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01005763 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005764 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005765 }
5766
Radek Krejcic071c542016-01-27 14:57:51 +01005767 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005768 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5769 if (!rc) {
5770 assert(*ret);
5771
5772 /* check status */
5773 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5774 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5775 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005776 } else if (ident) {
5777 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005778 if (lys_main_module(mod)->implemented) {
5779 /* in case of the implemented identity, maintain backlinks to it
5780 * from the base identities to make it available when resolving
5781 * data with the identity values (not implemented identity is not
5782 * allowed as an identityref value). */
5783 resolve_identity_backlink_update(ident, *ret);
5784 }
Radek Krejci219fa612016-08-15 10:36:51 +02005785 }
5786 } else if (rc == EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005787 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005788 if (type) {
5789 --type->info.ident.count;
5790 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005791 }
5792
Radek Krejci219fa612016-08-15 10:36:51 +02005793 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005794}
5795
Radek Krejci9e6af732017-04-27 14:40:25 +02005796/*
5797 * 1 - true (der is derived from base)
5798 * 0 - false (der is not derived from base)
5799 */
5800static int
5801search_base_identity(struct lys_ident *der, struct lys_ident *base)
5802{
5803 int i;
5804
5805 if (der == base) {
5806 return 1;
5807 } else {
5808 for(i = 0; i < der->base_size; i++) {
5809 if (search_base_identity(der->base[i], base) == 1) {
5810 return 1;
5811 }
5812 }
5813 }
5814
5815 return 0;
5816}
5817
Michal Vasko730dfdf2015-08-11 14:48:05 +02005818/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005819 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005820 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005821 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005822 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005823 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005824 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005825 *
5826 * @return Pointer to the identity resolvent, NULL on error.
5827 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005828struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005829resolve_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 +02005830{
Radek Krejci9e6af732017-04-27 14:40:25 +02005831 const char *mod_name, *name;
Michal Vasko08767f72017-10-06 14:38:08 +02005832 char *str;
Radek Krejcidce5f972017-09-12 15:47:49 +02005833 int mod_name_len, nam_len, rc;
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005834 int need_implemented = 0;
Michal Vasko4ea8de22020-01-27 13:53:28 +01005835 unsigned int i, j, found;
Michal Vaskof2d43962016-09-02 11:10:16 +02005836 struct lys_ident *der, *cur;
Andrew Langefeld8f50a2d2018-05-23 17:16:12 -05005837 struct lys_module *imod = NULL, *m, *tmod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005838 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005839
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005840 assert(type && ident_name && mod);
Michal Vasko53b7da02018-02-13 15:28:42 +01005841 ctx = mod->ctx;
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005842
Michal Vaskobb24f282019-09-02 12:54:30 +02005843 if (!type || (!type->info.ident.count && !type->der->module) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005844 return NULL;
5845 }
5846
Michal Vasko50576712017-07-28 12:28:33 +02005847 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005848 if (rc < 1) {
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005849 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005850 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005851 } else if (rc < (signed)strlen(ident_name)) {
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005852 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005853 return NULL;
5854 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005855
5856 m = lys_main_module(mod); /* shortcut */
5857 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5858 /* identity is defined in the same module as node */
5859 imod = m;
5860 } else if (dflt) {
5861 /* solving identityref in default definition in schema -
5862 * find the identity's module in the imported modules list to have a correct revision */
5863 for (i = 0; i < mod->imp_size; i++) {
5864 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5865 imod = mod->imp[i].module;
5866 break;
5867 }
5868 }
Andrew Langefeld8f50a2d2018-05-23 17:16:12 -05005869
5870 /* We may need to pull it from the module that the typedef came from */
Michal Vaskobb24f282019-09-02 12:54:30 +02005871 if (!imod && type && type->der->module) {
Andrew Langefeld8f50a2d2018-05-23 17:16:12 -05005872 tmod = type->der->module;
5873 for (i = 0; i < tmod->imp_size; i++) {
5874 if (!strncmp(mod_name, tmod->imp[i].module->name, mod_name_len) && !tmod->imp[i].module->name[mod_name_len]) {
5875 imod = tmod->imp[i].module;
5876 break;
5877 }
5878 }
5879 }
Michal Vaskode3a8ff2019-09-04 13:34:59 +02005880
5881 /* it can still be a default value in a foreign grouping */
5882 if (!imod) {
5883 str = strndup(mod_name, mod_name_len);
5884 imod = (struct lys_module *)ly_ctx_get_module(ctx, str, NULL, 1);
5885 free(str);
5886 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005887 } else {
Michal Vasko08767f72017-10-06 14:38:08 +02005888 /* solving identityref in data - get the module from the context */
5889 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5890 imod = mod->ctx->models.list[i];
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005891 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
Radek Krejci9e6af732017-04-27 14:40:25 +02005892 break;
5893 }
Michal Vasko08767f72017-10-06 14:38:08 +02005894 imod = NULL;
5895 }
Radek Krejci5ba05102017-10-26 15:02:52 +02005896 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5897 /* we are currently parsing some module and checking XPath or a default value,
5898 * so take this module into account */
5899 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5900 imod = mod->ctx->models.parsing_sub_modules[i];
5901 if (imod->type) {
5902 /* skip submodules */
5903 continue;
5904 }
5905 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5906 break;
5907 }
5908 imod = NULL;
5909 }
5910 }
Michal Vasko08767f72017-10-06 14:38:08 +02005911 }
5912
Michal Vasko53b7da02018-02-13 15:28:42 +01005913 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
Michal Vasko08767f72017-10-06 14:38:08 +02005914 /* the needed module was not found, but it may have been expected so call the data callback */
5915 if (imod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005916 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci58523dc2017-10-27 10:00:17 +02005917 } else if (mod_name) {
Michal Vasko08767f72017-10-06 14:38:08 +02005918 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01005919 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
Michal Vasko08767f72017-10-06 14:38:08 +02005920 free(str);
Radek Krejci9e6af732017-04-27 14:40:25 +02005921 }
5922 }
5923 if (!imod) {
5924 goto fail;
5925 }
5926
Michal Vasko4ea8de22020-01-27 13:53:28 +01005927 /* find the type with base definitions */
5928 while (!type->info.ident.count && type->der) {
5929 type = &type->der->type;
5930 }
5931 if (!type->info.ident.count) {
5932 goto fail;
5933 }
5934
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005935 if (m != imod || lys_main_module(type->parent->module) != mod) {
Michal Vasko08767f72017-10-06 14:38:08 +02005936 /* the type is not referencing the same schema,
Radek Krejci9e6af732017-04-27 14:40:25 +02005937 * THEN, we may need to make the module with the identity implemented, but only if it really
5938 * contains the identity */
5939 if (!imod->implemented) {
5940 cur = NULL;
5941 /* get the identity in the module */
5942 for (i = 0; i < imod->ident_size; i++) {
5943 if (!strcmp(name, imod->ident[i].name)) {
5944 cur = &imod->ident[i];
5945 break;
5946 }
5947 }
5948 if (!cur) {
5949 /* go through includes */
5950 for (j = 0; j < imod->inc_size; j++) {
5951 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5952 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5953 cur = &imod->inc[j].submodule->ident[i];
5954 break;
5955 }
5956 }
5957 }
5958 if (!cur) {
5959 goto fail;
5960 }
5961 }
5962
5963 /* check that identity is derived from one of the type's base */
5964 while (type->der) {
5965 for (i = 0; i < type->info.ident.count; i++) {
5966 if (search_base_identity(cur, type->info.ident.ref[i])) {
5967 /* cur's base matches the type's base */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005968 need_implemented = 1;
Radek Krejci9e6af732017-04-27 14:40:25 +02005969 goto match;
5970 }
5971 }
5972 type = &type->der->type;
5973 }
5974 /* matching base not found */
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005975 LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identity used as identityref value is not implemented.");
Radek Krejci9e6af732017-04-27 14:40:25 +02005976 goto fail;
5977 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005978 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005979
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005980 /* go through all the derived types of all the bases */
Michal Vasko4ea8de22020-01-27 13:53:28 +01005981 found = 0;
5982 for (i = 0; i < type->info.ident.count; ++i) {
5983 cur = type->info.ident.ref[i];
5984 if (cur->der) {
5985 /* there are some derived identities */
5986 for (j = 0; j < cur->der->number; j++) {
5987 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
5988 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
5989 /* we have a match on this base */
5990 ++found;
5991 break;
Michal Vaskof2d43962016-09-02 11:10:16 +02005992 }
5993 }
Michal Vaskobd2e2d32020-03-09 11:57:39 +01005994 } else {
5995 LOGWRN(ctx, "Identity \"%s\" has no derived identities, identityref with this base can never be instatiated.",
5996 cur->name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005997 }
Michal Vasko4ea8de22020-01-27 13:53:28 +01005998 }
5999 if (found == type->info.ident.count) {
6000 /* match found for all bases */
6001 cur = der;
6002 goto match;
Michal Vaskobd2e2d32020-03-09 11:57:39 +01006003 } else {
Michal Vasko4ea8de22020-01-27 13:53:28 +01006004 LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identityref value is not derived from all its bases.");
6005 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006006 }
6007
Radek Krejci9e6af732017-04-27 14:40:25 +02006008fail:
Michal Vaskoae4b7d32018-07-13 12:21:01 +02006009 LOGVAL(ctx, LYE_INRESOLV, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006010 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02006011
6012match:
Michal Vasko8dfaf7c2020-09-10 09:26:02 +02006013 if (!dflt) {
6014 for (i = 0; i < cur->iffeature_size; i++) {
6015 if (!resolve_iffeature(&cur->iffeature[i])) {
6016 if (node) {
6017 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
6018 }
Michal Vasko83cea222020-09-11 15:50:43 +02006019 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its %d. if-feature condition.",
6020 cur->name, i);
Michal Vasko8dfaf7c2020-09-10 09:26:02 +02006021 return NULL;
Michal Vaskoae4b7d32018-07-13 12:21:01 +02006022 }
Radek Krejcif1ee2e22016-08-02 16:36:48 +02006023 }
6024 }
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006025 if (need_implemented) {
6026 if (dflt) {
Michal Vasko0f437062018-06-08 15:52:39 +02006027 /* later try to make the module implemented */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006028 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
6029 imod->name, cur->name, mod->name);
Michal Vasko0f437062018-06-08 15:52:39 +02006030 /* to be more effective we should use UNRES_MOD_IMPLEMENT but that would require changing prototype of
6031 * several functions with little gain */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006032 if (lys_set_implemented(imod)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006033 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006034 imod->name, cur->name);
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006035 goto fail;
6036 }
6037 } else {
6038 /* just say that it was found, but in a non-implemented module */
Michal Vasko53b7da02018-02-13 15:28:42 +01006039 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02006040 lys_main_module(cur->module)->name);
Radek Krejci9e6af732017-04-27 14:40:25 +02006041 goto fail;
6042 }
6043 }
Michal Vaskof2d43962016-09-02 11:10:16 +02006044 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006045}
6046
Michal Vasko730dfdf2015-08-11 14:48:05 +02006047/**
Michal Vaskobb211122015-08-19 14:03:11 +02006048 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006049 *
Michal Vaskobb211122015-08-19 14:03:11 +02006050 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006051 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006052 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006053 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006054 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006055static int
Radek Krejci48464ed2016-03-17 15:44:09 +01006056resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006057{
Radek Krejci93def382017-05-24 15:33:48 +02006058 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01006059 struct lys_node *par_grp;
Michal Vasko53b7da02018-02-13 15:28:42 +01006060 struct ly_ctx *ctx = uses->module->ctx;
Michal Vaskoe91afce2015-08-12 12:21:00 +02006061
Radek Krejci6ff885d2017-01-03 14:06:22 +01006062 /* 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 +02006063 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
6064 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
6065 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02006066 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoa9792722018-06-28 09:01:02 +02006067 if (par_grp && ly_strequal(par_grp->name, uses->name, 1)) {
6068 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
6069 return -1;
6070 }
Michal Vaskoe91afce2015-08-12 12:21:00 +02006071
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006072 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01006073 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
6074 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006075 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01006076 return -1;
6077 } else if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006078 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01006079 return -1;
6080 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006081 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02006082 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006083 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006084 return -1;
6085 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006086 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02006087 }
Michal Vasko53b7da02018-02-13 15:28:42 +01006088 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01006089 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02006090 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006091 }
6092
Radek Krejci93def382017-05-24 15:33:48 +02006093 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006094 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02006095 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006096 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006097 return -1;
6098 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006099 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02006100 } else {
6101 /* instantiate grouping only when it is completely resolved */
6102 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02006103 }
Michal Vaskoa9792722018-06-28 09:01:02 +02006104 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006105 return EXIT_FAILURE;
6106 }
6107
Radek Krejci48464ed2016-03-17 15:44:09 +01006108 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006109 if (!rc) {
6110 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01006111 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02006112 assert(((struct lys_node_grp *)par_grp)->unres_count);
6113 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01006114 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006115 }
Radek Krejcicf509982015-12-15 09:22:44 +01006116
6117 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01006118 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01006119 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01006120 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01006121 return -1;
6122 }
6123
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006124 return EXIT_SUCCESS;
6125 }
6126
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006127 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006128}
6129
Michal Vasko730dfdf2015-08-11 14:48:05 +02006130/**
Michal Vasko9957e592015-08-17 15:04:09 +02006131 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006132 *
Michal Vaskobb211122015-08-19 14:03:11 +02006133 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006134 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006135 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006136 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006137 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006138static int
Radek Krejci48464ed2016-03-17 15:44:09 +01006139resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006140{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006141 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01006142 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02006143 char *s = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01006144 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006145
6146 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02006147 assert(keys_str);
6148
Radek Krejci5c08a992016-11-02 13:30:04 +01006149 if (!list->child) {
6150 /* no child, possible forward reference */
Michal Vasko53b7da02018-02-13 15:28:42 +01006151 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Radek Krejci5c08a992016-11-02 13:30:04 +01006152 return EXIT_FAILURE;
6153 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006154 /* get the key name */
6155 if ((value = strpbrk(keys_str, " \t\n"))) {
6156 len = value - keys_str;
6157 while (isspace(value[0])) {
6158 value++;
6159 }
6160 } else {
6161 len = strlen(keys_str);
6162 }
6163
Michal Vaskobb520442017-05-23 10:55:18 +02006164 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
Michal Vasko32fb4992019-03-08 08:55:16 +01006165 LYS_GETNEXT_NOSTATECHECK, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006166 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006167 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02006168 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006169 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006170
Radek Krejci48464ed2016-03-17 15:44:09 +01006171 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006172 /* check_key logs */
6173 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006174 }
6175
Radek Krejcicf509982015-12-15 09:22:44 +01006176 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01006177 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01006178 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
6179 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01006180 return -1;
6181 }
6182
Radek Krejcia98048c2017-05-24 16:35:48 +02006183 /* default value - is ignored, keep it but print a warning */
6184 if (list->keys[i]->dflt) {
6185 /* log is not hidden only in case this resolving fails and in such a case
6186 * we cannot get here
6187 */
Michal Vasko53b7da02018-02-13 15:28:42 +01006188 assert(log_opt == ILO_STORE);
6189 log_opt = ILO_LOG;
6190 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
Michal Vasko395b0a02018-01-22 09:36:20 +01006191 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
Michal Vasko53b7da02018-02-13 15:28:42 +01006192 log_opt = ILO_STORE;
Radek Krejcia98048c2017-05-24 16:35:48 +02006193 free(s);
6194 }
6195
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006196 /* prepare for next iteration */
6197 while (value && isspace(value[0])) {
6198 value++;
6199 }
6200 keys_str = value;
6201 }
6202
Michal Vaskof02e3742015-08-05 16:27:02 +02006203 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006204}
6205
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006206/**
Michal Vaskobf19d252015-10-08 15:39:17 +02006207 * @brief Resolve (check) all must conditions of \p node.
6208 * Logs directly.
6209 *
6210 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006211 * @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 +02006212 *
6213 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
6214 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006215static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006216resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02006217{
Michal Vaskobf19d252015-10-08 15:39:17 +02006218 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006219 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02006220 struct lys_restr *must;
6221 struct lyxp_set set;
Michal Vasko53b7da02018-02-13 15:28:42 +01006222 struct ly_ctx *ctx = node->schema->module->ctx;
Michal Vaskobf19d252015-10-08 15:39:17 +02006223
6224 assert(node);
6225 memset(&set, 0, sizeof set);
6226
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006227 if (inout_parent) {
6228 for (schema = lys_parent(node->schema);
6229 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
6230 schema = lys_parent(schema));
6231 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006232 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006233 return -1;
6234 }
6235 must_size = ((struct lys_node_inout *)schema)->must_size;
6236 must = ((struct lys_node_inout *)schema)->must;
6237
6238 /* context node is the RPC/action */
6239 node = node->parent;
6240 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006241 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006242 return -1;
6243 }
6244 } else {
6245 switch (node->schema->nodetype) {
6246 case LYS_CONTAINER:
6247 must_size = ((struct lys_node_container *)node->schema)->must_size;
6248 must = ((struct lys_node_container *)node->schema)->must;
6249 break;
6250 case LYS_LEAF:
6251 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
6252 must = ((struct lys_node_leaf *)node->schema)->must;
6253 break;
6254 case LYS_LEAFLIST:
6255 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
6256 must = ((struct lys_node_leaflist *)node->schema)->must;
6257 break;
6258 case LYS_LIST:
6259 must_size = ((struct lys_node_list *)node->schema)->must_size;
6260 must = ((struct lys_node_list *)node->schema)->must;
6261 break;
6262 case LYS_ANYXML:
6263 case LYS_ANYDATA:
6264 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
6265 must = ((struct lys_node_anydata *)node->schema)->must;
6266 break;
6267 case LYS_NOTIF:
6268 must_size = ((struct lys_node_notif *)node->schema)->must_size;
6269 must = ((struct lys_node_notif *)node->schema)->must;
6270 break;
6271 default:
6272 must_size = 0;
6273 break;
6274 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006275 }
6276
6277 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006278 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006279 return -1;
6280 }
6281
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006282 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02006283
Michal Vasko8146d4c2016-05-09 15:50:29 +02006284 if (!set.val.bool) {
Michal Vaskoc04173b2018-03-09 10:43:22 +01006285 if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006286 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
6287 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006288 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006289 if (must[i].emsg) {
Michal Vaskob4b31f62018-11-23 11:49:20 +01006290 ly_vlog_str(ctx, LY_VLOG_PREV, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006291 }
6292 if (must[i].eapptag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006293 ly_err_last_set_apptag(ctx, must[i].eapptag);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006294 }
6295 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02006296 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006297 }
6298 }
6299
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006300 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02006301}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006302
Michal Vaskobf19d252015-10-08 15:39:17 +02006303/**
Michal Vasko508a50d2016-09-07 14:50:33 +02006304 * @brief Resolve (find) when condition schema context node. Does not log.
6305 *
6306 * @param[in] schema Schema node with the when condition.
6307 * @param[out] ctx_snode When schema context node.
6308 * @param[out] ctx_snode_type Schema context node type.
6309 */
6310void
6311resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
6312{
6313 const struct lys_node *sparent;
6314
6315 /* find a not schema-only node */
6316 *ctx_snode_type = LYXP_NODE_ELEM;
6317 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
6318 if (schema->nodetype == LYS_AUGMENT) {
6319 sparent = ((struct lys_node_augment *)schema)->target;
6320 } else {
6321 sparent = schema->parent;
6322 }
6323 if (!sparent) {
6324 /* context node is the document root (fake root in our case) */
6325 if (schema->flags & LYS_CONFIG_W) {
6326 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
6327 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02006328 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02006329 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02006330 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskocb45f472018-02-12 10:47:42 +01006331 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
Michal Vasko508a50d2016-09-07 14:50:33 +02006332 break;
6333 }
6334 schema = sparent;
6335 }
6336
6337 *ctx_snode = (struct lys_node *)schema;
6338}
6339
6340/**
Michal Vaskocf024702015-10-08 15:01:42 +02006341 * @brief Resolve (find) when condition context node. Does not log.
6342 *
6343 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02006344 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02006345 * @param[out] ctx_node Context node.
6346 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02006347 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02006348 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02006349 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02006350static int
6351resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
6352 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006353{
Michal Vaskocf024702015-10-08 15:01:42 +02006354 struct lyd_node *parent;
6355 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006356 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02006357 uint16_t i, data_depth, schema_depth;
6358
Michal Vasko508a50d2016-09-07 14:50:33 +02006359 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02006360
Michal Vaskofe989752016-09-08 08:47:26 +02006361 if (node_type == LYXP_NODE_ELEM) {
6362 /* standard element context node */
6363 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
6364 for (sparent = schema, schema_depth = 0;
6365 sparent;
6366 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
6367 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
6368 ++schema_depth;
6369 }
Michal Vaskocf024702015-10-08 15:01:42 +02006370 }
Michal Vaskofe989752016-09-08 08:47:26 +02006371 if (data_depth < schema_depth) {
6372 return -1;
6373 }
Michal Vaskocf024702015-10-08 15:01:42 +02006374
Michal Vasko956e8542016-08-26 09:43:35 +02006375 /* find the corresponding data node */
6376 for (i = 0; i < data_depth - schema_depth; ++i) {
6377 node = node->parent;
6378 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02006379 if (node->schema != schema) {
6380 return -1;
6381 }
Michal Vaskofe989752016-09-08 08:47:26 +02006382 } else {
6383 /* root context node */
6384 while (node->parent) {
6385 node = node->parent;
6386 }
6387 while (node->prev->next) {
6388 node = node->prev;
6389 }
Michal Vaskocf024702015-10-08 15:01:42 +02006390 }
6391
Michal Vaskoa59495d2016-08-22 09:18:58 +02006392 *ctx_node = node;
6393 *ctx_node_type = node_type;
6394 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02006395}
6396
Michal Vasko76c3bd32016-08-24 16:02:52 +02006397/**
6398 * @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 +01006399 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02006400 *
6401 * @param[in] snode Schema node, whose children instances need to be unlinked.
6402 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
6403 * it is moved to point to another sibling still in the original tree.
6404 * @param[in,out] ctx_node When context node, adjusted if needed.
6405 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
6406 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
6407 * Ordering may change, but there will be no semantic change.
6408 *
6409 * @return EXIT_SUCCESS on success, -1 on error.
6410 */
6411static int
6412resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
6413 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
6414{
6415 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006416 const struct lys_node *slast;
Michal Vasko53b7da02018-02-13 15:28:42 +01006417 struct ly_ctx *ctx = snode->module->ctx;
Michal Vasko76c3bd32016-08-24 16:02:52 +02006418
6419 switch (snode->nodetype) {
6420 case LYS_AUGMENT:
6421 case LYS_USES:
6422 case LYS_CHOICE:
6423 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006424 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01006425 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006426 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6427 continue;
6428 }
6429
6430 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006431 return -1;
6432 }
6433 }
6434 break;
6435 case LYS_CONTAINER:
6436 case LYS_LIST:
6437 case LYS_LEAF:
6438 case LYS_LEAFLIST:
6439 case LYS_ANYXML:
6440 case LYS_ANYDATA:
6441 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6442 if (elem->schema == snode) {
6443
6444 if (elem == *ctx_node) {
6445 /* We are going to unlink our context node! This normally cannot happen,
6446 * but we use normal top-level data nodes for faking a document root node,
6447 * so if this is the context node, we just use the next top-level node.
6448 * Additionally, it can even happen that there are no top-level data nodes left,
6449 * all were unlinked, so in this case we pass NULL as the context node/data tree,
6450 * lyxp_eval() can handle this special situation.
6451 */
6452 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006453 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006454 return -1;
6455 }
6456
6457 if (elem->prev == elem) {
6458 /* unlinking last top-level element, use an empty data tree */
6459 *ctx_node = NULL;
6460 } else {
6461 /* in this case just use the previous/last top-level data node */
6462 *ctx_node = elem->prev;
6463 }
6464 } else if (elem == *node) {
6465 /* We are going to unlink the currently processed node. This does not matter that
6466 * much, but we would lose access to the original data tree, so just move our
6467 * pointer somewhere still inside it.
6468 */
6469 if ((*node)->prev != *node) {
6470 *node = (*node)->prev;
6471 } else {
6472 /* the processed node with sibings were all unlinked, oh well */
6473 *node = NULL;
6474 }
6475 }
6476
6477 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01006478 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006479 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006480 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006481 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006482 return -1;
6483 }
6484 } else {
6485 *unlinked_nodes = elem;
6486 }
6487
6488 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6489 /* there can be only one instance */
6490 break;
6491 }
6492 }
6493 }
6494 break;
6495 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006496 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006497 return -1;
6498 }
6499
6500 return EXIT_SUCCESS;
6501}
6502
6503/**
6504 * @brief Relink the unlinked nodes back.
6505 *
6506 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6507 * we simply need a sibling from the original data tree.
6508 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6509 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6510 * or the sibling of \p unlinked_nodes.
6511 *
6512 * @return EXIT_SUCCESS on success, -1 on error.
6513 */
6514static int
6515resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6516{
6517 struct lyd_node *elem;
6518
6519 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006520 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006521 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006522 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006523 return -1;
6524 }
6525 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006526 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006527 return -1;
6528 }
6529 }
6530 }
6531
6532 return EXIT_SUCCESS;
6533}
6534
Radek Krejci03b71f72016-03-16 11:10:09 +01006535int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006536resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01006537{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006538 int ret = 0;
6539 uint8_t must_size;
6540 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02006541
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006542 assert(node);
6543
6544 schema = node->schema;
6545
6546 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02006547 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01006548 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006549 must_size = ((struct lys_node_container *)schema)->must_size;
6550 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006551 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006552 must_size = ((struct lys_node_leaf *)schema)->must_size;
6553 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006554 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006555 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6556 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006557 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006558 must_size = ((struct lys_node_list *)schema)->must_size;
6559 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006560 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02006561 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006562 must_size = ((struct lys_node_anydata *)schema)->must_size;
6563 break;
6564 case LYS_NOTIF:
6565 must_size = ((struct lys_node_notif *)schema)->must_size;
6566 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006567 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006568 must_size = 0;
6569 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006570 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006571
6572 if (must_size) {
6573 ++ret;
6574 }
6575
6576 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6577 if (!node->prev->next) {
6578 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6579 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6580 ret += 0x2;
6581 }
6582 }
6583
6584 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006585}
6586
Michal Vaskodd962292018-09-10 08:53:01 +02006587static struct lys_when *
6588snode_get_when(const struct lys_node *schema)
6589{
6590 switch (schema->nodetype) {
6591 case LYS_CONTAINER:
6592 return ((struct lys_node_container *)schema)->when;
6593 case LYS_CHOICE:
6594 return ((struct lys_node_choice *)schema)->when;
6595 case LYS_LEAF:
6596 return ((struct lys_node_leaf *)schema)->when;
6597 case LYS_LEAFLIST:
6598 return ((struct lys_node_leaflist *)schema)->when;
6599 case LYS_LIST:
6600 return ((struct lys_node_list *)schema)->when;
6601 case LYS_ANYDATA:
6602 case LYS_ANYXML:
6603 return ((struct lys_node_anydata *)schema)->when;
6604 case LYS_CASE:
6605 return ((struct lys_node_case *)schema)->when;
6606 case LYS_USES:
6607 return ((struct lys_node_uses *)schema)->when;
6608 case LYS_AUGMENT:
6609 return ((struct lys_node_augment *)schema)->when;
6610 default:
6611 return NULL;
6612 }
6613}
6614
Radek Krejci01696bf2016-03-18 13:19:36 +01006615int
Radek Krejci46165822016-08-26 14:06:27 +02006616resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006617{
Radek Krejci46165822016-08-26 14:06:27 +02006618 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006619
Radek Krejci46165822016-08-26 14:06:27 +02006620 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006621
Michal Vaskodd962292018-09-10 08:53:01 +02006622 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && snode_get_when(schema)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006623 return 1;
6624 }
6625
Radek Krejci46165822016-08-26 14:06:27 +02006626 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006627 goto check_augment;
6628
Radek Krejci46165822016-08-26 14:06:27 +02006629 while (parent) {
6630 /* stop conditions */
6631 if (!mode) {
6632 /* stop on node that can be instantiated in data tree */
6633 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6634 break;
6635 }
6636 } else {
6637 /* stop on the specified node */
6638 if (parent == stop) {
6639 break;
6640 }
6641 }
6642
Michal Vaskodd962292018-09-10 08:53:01 +02006643 if (snode_get_when(parent)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006644 return 1;
6645 }
6646check_augment:
6647
Michal Vaskodd962292018-09-10 08:53:01 +02006648 if (parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && snode_get_when(parent->parent)) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006649 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006650 }
6651 parent = lys_parent(parent);
6652 }
6653
6654 return 0;
6655}
6656
Michal Vaskocf024702015-10-08 15:01:42 +02006657/**
6658 * @brief Resolve (check) all when conditions relevant for \p node.
6659 * Logs directly.
6660 *
6661 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02006662 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6663 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02006664 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006665 * @return
6666 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02006667 * 0 - all "when" statements true
6668 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01006669 * 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 +02006670 */
Radek Krejci46165822016-08-26 14:06:27 +02006671int
Michal Vasko0b963112017-08-11 12:45:36 +02006672resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02006673{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006674 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006675 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006676 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006677 enum lyxp_node_type ctx_node_type;
Michal Vasko53b7da02018-02-13 15:28:42 +01006678 struct ly_ctx *ctx = node->schema->module->ctx;
Radek Krejci51093642016-03-29 10:14:59 +02006679 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006680
6681 assert(node);
6682 memset(&set, 0, sizeof set);
6683
Michal Vaskodd962292018-09-10 08:53:01 +02006684 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && snode_get_when(node->schema)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006685 /* make the node dummy for the evaluation */
6686 node->validity |= LYD_VAL_INUSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006687 rc = lyxp_eval(snode_get_when(node->schema)->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006688 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006689 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006690 if (rc) {
6691 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006692 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006693 }
Radek Krejci51093642016-03-29 10:14:59 +02006694 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006695 }
6696
Radek Krejci03b71f72016-03-16 11:10:09 +01006697 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006698 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006699 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006700 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006701 if ((ignore_fail == 1) || ((snode_get_when(node->schema)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
Michal Vaskoc04173b2018-03-09 10:43:22 +01006702 && (ignore_fail == 2))) {
Michal Vaskodd962292018-09-10 08:53:01 +02006703 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(node->schema)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006704 } else {
Michal Vaskodd962292018-09-10 08:53:01 +02006705 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006706 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006707 *failed_when = snode_get_when(node->schema);
Michal Vasko0b963112017-08-11 12:45:36 +02006708 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006709 goto cleanup;
6710 }
Michal Vaskocf024702015-10-08 15:01:42 +02006711 }
Radek Krejci51093642016-03-29 10:14:59 +02006712
6713 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006714 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006715 }
6716
Michal Vasko90fc2a32016-08-24 15:58:58 +02006717 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006718 goto check_augment;
6719
6720 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006721 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
Michal Vaskodd962292018-09-10 08:53:01 +02006722 if (snode_get_when(sparent)) {
Michal Vaskocf024702015-10-08 15:01:42 +02006723 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006724 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006725 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006726 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006727 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006728 }
6729 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006730
6731 unlinked_nodes = NULL;
6732 /* we do not want our node pointer to change */
6733 tmp_node = node;
6734 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6735 if (rc) {
6736 goto cleanup;
6737 }
6738
Michal Vaskodd962292018-09-10 08:53:01 +02006739 rc = lyxp_eval(snode_get_when(sparent)->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006740 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006741
6742 if (unlinked_nodes && ctx_node) {
6743 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6744 rc = -1;
6745 goto cleanup;
6746 }
6747 }
6748
Radek Krejci03b71f72016-03-16 11:10:09 +01006749 if (rc) {
6750 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006751 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006752 }
Radek Krejci51093642016-03-29 10:14:59 +02006753 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006754 }
6755
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006756 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006757 if (!set.val.bool) {
Michal Vaskodd962292018-09-10 08:53:01 +02006758 if ((ignore_fail == 1) || ((snode_get_when(sparent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6759 && (ignore_fail == 2))) {
6760 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(sparent)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006761 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006762 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006763 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006764 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006765 *failed_when = snode_get_when(sparent);
Michal Vasko0b963112017-08-11 12:45:36 +02006766 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006767 goto cleanup;
6768 }
Michal Vaskocf024702015-10-08 15:01:42 +02006769 }
Radek Krejci51093642016-03-29 10:14:59 +02006770
6771 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006772 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006773 }
6774
6775check_augment:
Michal Vaskodd962292018-09-10 08:53:01 +02006776 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && snode_get_when(sparent->parent))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006777 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006778 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006779 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006780 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006781 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006782 }
6783 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006784
6785 unlinked_nodes = NULL;
6786 tmp_node = node;
6787 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6788 if (rc) {
6789 goto cleanup;
6790 }
6791
Michal Vaskodd962292018-09-10 08:53:01 +02006792 rc = lyxp_eval(snode_get_when(sparent->parent)->cond, ctx_node, ctx_node_type,
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006793 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006794
6795 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6796 * so the tree did not actually change and there is nothing for us to do
6797 */
6798 if (unlinked_nodes && ctx_node) {
6799 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6800 rc = -1;
6801 goto cleanup;
6802 }
6803 }
6804
Radek Krejci03b71f72016-03-16 11:10:09 +01006805 if (rc) {
6806 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006807 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006808 }
Radek Krejci51093642016-03-29 10:14:59 +02006809 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006810 }
6811
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006812 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006813 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006814 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006815 if ((ignore_fail == 1) || ((snode_get_when(sparent->parent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
Michal Vaskoc04173b2018-03-09 10:43:22 +01006816 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006817 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vaskodd962292018-09-10 08:53:01 +02006818 snode_get_when(sparent->parent)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006819 } else {
Michal Vaskodd962292018-09-10 08:53:01 +02006820 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006821 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006822 *failed_when = snode_get_when(sparent->parent);
Michal Vasko0b963112017-08-11 12:45:36 +02006823 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006824 goto cleanup;
6825 }
Michal Vaskocf024702015-10-08 15:01:42 +02006826 }
Radek Krejci51093642016-03-29 10:14:59 +02006827
6828 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006829 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006830 }
6831
Michal Vasko90fc2a32016-08-24 15:58:58 +02006832 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006833 }
6834
Radek Krejci0b7704f2016-03-18 12:16:14 +01006835 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006836
Radek Krejci51093642016-03-29 10:14:59 +02006837cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006838 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006839 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006840 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006841}
6842
Radek Krejcicbb473e2016-09-16 14:48:32 +02006843static int
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006844check_type_union_leafref(struct lys_type *type)
6845{
6846 uint8_t i;
6847
6848 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6849 /* go through unions and look for leafref */
6850 for (i = 0; i < type->info.uni.count; ++i) {
6851 switch (type->info.uni.types[i].base) {
6852 case LY_TYPE_LEAFREF:
6853 return 1;
6854 case LY_TYPE_UNION:
6855 if (check_type_union_leafref(&type->info.uni.types[i])) {
6856 return 1;
6857 }
6858 break;
6859 default:
6860 break;
6861 }
6862 }
6863
6864 return 0;
6865 }
6866
6867 /* just inherit the flag value */
6868 return type->der->has_union_leafref;
6869}
6870
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006871/**
Michal Vaskobb211122015-08-19 14:03:11 +02006872 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006873 *
6874 * @param[in] mod Main module.
6875 * @param[in] item Item to resolve. Type determined by \p type.
6876 * @param[in] type Type of the unresolved item.
6877 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006878 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006879 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006880 *
6881 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6882 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006883static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006884resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006885 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006886{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006887 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Michal Vasko53b7da02018-02-13 15:28:42 +01006888 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006889 unsigned int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01006890 struct ly_ctx * ctx = mod->ctx;
Radek Krejci80056d52017-01-05 13:13:33 +01006891 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006892 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006893 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006894
Radek Krejcic79c6b12016-07-26 15:11:49 +02006895 struct ly_set *refs, *procs;
6896 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006897 struct lys_ident *ident;
6898 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006899 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006900 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006901 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006902 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006903 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006904 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006905 struct lys_ext_instance *ext, **extlist;
6906 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006907
6908 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006909 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006910 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006911 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006912 ident = item;
6913
Radek Krejci018f1f52016-08-03 16:01:20 +02006914 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006915 break;
6916 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006917 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006918 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006919 stype = item;
6920
Radek Krejci018f1f52016-08-03 16:01:20 +02006921 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006922 break;
6923 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006924 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006925 stype = item;
6926
Michal Vasko74083ec2018-06-15 10:00:12 +02006927 rc = resolve_schema_leafref(stype, node, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006928 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006929 case UNRES_TYPE_DER_EXT:
6930 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006931 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006932 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006933 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006934 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006935 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006936 /* parent */
6937 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006938 stype = item;
6939
Michal Vasko88c29542015-11-27 14:57:53 +01006940 /* HACK type->der is temporarily unparsed type statement */
6941 yin = (struct lyxml_elem *)stype->der;
6942 stype->der = NULL;
6943
Pavol Vicana0e4e672016-02-24 12:20:04 +01006944 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6945 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006946 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006947
6948 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006949 /* may try again later */
6950 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006951 } else {
6952 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006953 lydict_remove(ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006954 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006955 }
6956
Michal Vasko88c29542015-11-27 14:57:53 +01006957 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006958 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006959 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006960 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006961 lyxml_free(ctx, yin);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006962 } else {
6963 /* may try again later, put all back how it was */
6964 stype->der = (struct lys_tpdf *)yin;
6965 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006966 }
Radek Krejcic13db382016-08-16 10:52:42 +02006967 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006968 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006969 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006970 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
Radek Krejci2c2fce82016-08-01 13:52:26 +02006971 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006972
6973 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6974 /* fill typedef union leafref flag */
6975 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6976 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6977 /* copy the type in case it has union leafref flag */
6978 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006979 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006980 return -1;
6981 }
6982 }
Michal Vasko101658e2018-06-05 15:05:54 +02006983 } else if (rc == EXIT_FAILURE && !(stype->value_flags & LY_VALUE_UNRESGRP)) {
Radek Krejcic13db382016-08-16 10:52:42 +02006984 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6985 * 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 +02006986 * grouping. The grouping cannot be used unless the unres counter is 0.
Michal Vasko70bf8e52018-03-26 11:32:33 +02006987 * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006988 * of the type's base member. */
6989 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6990 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006991 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006992 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006993 return -1;
6994 }
Michal Vasko101658e2018-06-05 15:05:54 +02006995 stype->value_flags |= LY_VALUE_UNRESGRP;
Radek Krejcic13db382016-08-16 10:52:42 +02006996 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006997 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006998 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006999 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007000 iff_data = str_snode;
7001 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02007002 if (!rc) {
7003 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02007004 if (iff_data->infeature) {
7005 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
7006 feat = *((struct lys_feature **)item);
7007 if (!feat->depfeatures) {
7008 feat->depfeatures = ly_set_new();
7009 }
Radek Krejci85a54be2016-10-20 12:39:56 +02007010 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02007011 }
7012 /* cleanup temporary data */
Michal Vasko53b7da02018-02-13 15:28:42 +01007013 lydict_remove(ctx, iff_data->fname);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007014 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02007015 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007016 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02007017 case UNRES_FEATURE:
7018 feat = (struct lys_feature *)item;
7019
7020 if (feat->iffeature_size) {
7021 refs = ly_set_new();
7022 procs = ly_set_new();
7023 ly_set_add(procs, feat, 0);
7024
7025 while (procs->number) {
7026 ref = procs->set.g[procs->number - 1];
7027 ly_set_rm_index(procs, procs->number - 1);
7028
7029 for (i = 0; i < ref->iffeature_size; i++) {
7030 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
7031 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02007032 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02007033 if (ref->iffeature[i].features[j - 1] == feat) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007034 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
Radek Krejcic79c6b12016-07-26 15:11:49 +02007035 goto featurecheckdone;
7036 }
7037
7038 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
7039 k = refs->number;
7040 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
7041 /* not yet seen feature, add it for processing */
7042 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
7043 }
7044 }
7045 } else {
7046 /* forward reference */
7047 rc = EXIT_FAILURE;
7048 goto featurecheckdone;
7049 }
7050 }
7051
7052 }
7053 }
7054 rc = EXIT_SUCCESS;
7055
7056featurecheckdone:
7057 ly_set_free(refs);
7058 ly_set_free(procs);
7059 }
7060
7061 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007062 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01007063 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007064 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01007065 case UNRES_TYPEDEF_DFLT:
7066 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02007067 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007068 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02007069 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01007070 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc40a2092018-11-20 09:32:23 +01007071 if ((rc == EXIT_FAILURE) && !parent_type && (stype->base == LY_TYPE_LEAFREF)) {
Michal Vasko7d894922018-11-12 11:55:55 +01007072 for (par_grp = (struct lys_node *)stype->parent;
7073 par_grp && (par_grp->nodetype != LYS_GROUPING);
7074 par_grp = lys_parent(par_grp));
7075 if (par_grp) {
7076 /* checking default value in a grouping finished with forward reference means we cannot check the value */
7077 rc = EXIT_SUCCESS;
7078 }
7079 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007080 break;
7081 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02007082 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01007083 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02007084 choic = item;
7085
Radek Krejcie00d2312016-08-12 15:27:49 +02007086 if (!choic->dflt) {
7087 choic->dflt = resolve_choice_dflt(choic, expr);
7088 }
Michal Vasko7955b362015-09-04 14:18:15 +02007089 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02007090 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02007091 } else {
7092 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02007093 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007094 break;
7095 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01007096 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007097 break;
7098 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02007099 unique_info = (struct unres_list_uniq *)item;
7100 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007101 break;
Michal Vasko7178e692016-02-12 15:58:05 +01007102 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01007103 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01007104 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02007105 case UNRES_XPATH:
7106 node = (struct lys_node *)item;
Michal Vasko895c11f2018-03-12 11:35:58 +01007107 rc = check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02007108 break;
Michal Vasko0f437062018-06-08 15:52:39 +02007109 case UNRES_MOD_IMPLEMENT:
7110 rc = lys_make_implemented_r(mod, unres);
7111 break;
Radek Krejcie534c132016-11-23 13:32:31 +01007112 case UNRES_EXT:
7113 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01007114 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01007115 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01007116 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01007117 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01007118 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01007119 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01007120 if (eplugin) {
7121 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01007122 u = malloc(sizeof *u);
Michal Vasko53b7da02018-02-13 15:28:42 +01007123 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01007124 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01007125 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
fredgan31f56fd2019-09-26 14:34:03 +08007126 /* something really bad happened since the extension finalization is not actually
Radek Krejcib08bc172017-02-27 13:17:14 +01007127 * being resolved while adding into unres, so something more serious with the unres
7128 * list itself must happened */
7129 return -1;
7130 }
Radek Krejci80056d52017-01-05 13:13:33 +01007131 }
7132 }
Radek Krejci79685c92017-02-17 10:49:43 +01007133 }
7134 if (!rc || rc == -1) {
7135 /* cleanup on success or fatal error */
7136 if (ext_data->datatype == LYS_IN_YIN) {
7137 /* YIN */
Michal Vasko53b7da02018-02-13 15:28:42 +01007138 lyxml_free(ctx, ext_data->data.yin);
Radek Krejci79685c92017-02-17 10:49:43 +01007139 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01007140 /* YANG */
7141 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01007142 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01007143 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01007144 }
7145 break;
Radek Krejci80056d52017-01-05 13:13:33 +01007146 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01007147 u = (uint8_t *)str_snode;
7148 ext = (*(struct lys_ext_instance ***)item)[*u];
7149 free(u);
7150
Radek Krejci80056d52017-01-05 13:13:33 +01007151 eplugin = ext->def->plugin;
7152
7153 /* inherit */
7154 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
7155 root = (struct lys_node *)ext->parent;
7156 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
7157 LY_TREE_DFS_BEGIN(root->child, next, node) {
7158 /* first, check if the node already contain instance of the same extension,
7159 * in such a case we won't inherit. In case the node was actually defined as
7160 * augment data, we are supposed to check the same way also the augment node itself */
7161 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
7162 goto inherit_dfs_sibling;
7163 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
7164 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
7165 goto inherit_dfs_sibling;
7166 }
7167
7168 if (eplugin->check_inherit) {
7169 /* we have a callback to check the inheritance, use it */
7170 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
7171 case 0:
7172 /* yes - continue with the inheriting code */
7173 break;
7174 case 1:
7175 /* no - continue with the node's sibling */
7176 goto inherit_dfs_sibling;
7177 case 2:
7178 /* no, but continue with the children, just skip the inheriting code for this node */
7179 goto inherit_dfs_child;
7180 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007181 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
Radek Krejci80056d52017-01-05 13:13:33 +01007182 ext->def->module->name, ext->def->name, rc);
7183 }
7184 }
7185
7186 /* inherit the extension */
7187 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Michal Vasko53b7da02018-02-13 15:28:42 +01007188 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007189 extlist[node->ext_size] = malloc(sizeof **extlist);
Michal Vasko53b7da02018-02-13 15:28:42 +01007190 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007191 memcpy(extlist[node->ext_size], ext, sizeof *ext);
7192 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
7193
7194 node->ext = extlist;
7195 node->ext_size++;
7196
7197inherit_dfs_child:
7198 /* modification of - select element for the next run - children first */
7199 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
7200 next = NULL;
7201 } else {
7202 next = node->child;
7203 }
7204 if (!next) {
7205inherit_dfs_sibling:
7206 /* no children, try siblings */
7207 next = node->next;
7208 }
7209 while (!next) {
7210 /* go to the parent */
7211 node = lys_parent(node);
7212
7213 /* we are done if we are back in the root (the starter's parent */
7214 if (node == root) {
7215 break;
7216 }
7217
7218 /* parent is already processed, go to its sibling */
7219 next = node->next;
7220 }
7221 }
7222 }
7223 }
7224
7225 /* final check */
7226 if (eplugin->check_result) {
7227 if ((*eplugin->check_result)(ext)) {
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007228 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
Radek Krejci80056d52017-01-05 13:13:33 +01007229 return -1;
7230 }
7231 }
7232
7233 rc = 0;
7234 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007235 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007236 LOGINT(ctx);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007237 break;
7238 }
7239
Radek Krejci54081ce2016-08-12 15:21:47 +02007240 if (has_str && !rc) {
7241 /* the string is no more needed in case of success.
7242 * In case of forward reference, we will try to resolve the string later */
Michal Vasko53b7da02018-02-13 15:28:42 +01007243 lydict_remove(ctx, str_snode);
Radek Krejci4f78b532016-02-17 13:43:00 +01007244 }
7245
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007246 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007247}
7248
Michal Vaskof02e3742015-08-05 16:27:02 +02007249/* logs directly */
7250static void
Radek Krejci48464ed2016-03-17 15:44:09 +01007251print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007252{
Michal Vaskocb34dc62016-05-20 14:38:37 +02007253 struct lyxml_elem *xml;
7254 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007255 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01007256 const char *name = NULL;
7257 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007258
Michal Vaskof02e3742015-08-05 16:27:02 +02007259 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02007260 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007261 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007262 break;
7263 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007264 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007265 break;
7266 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007267 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
7268 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02007269 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01007270 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02007271 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02007272 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02007273 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
7274 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01007275 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007276 } else {
7277 LY_TREE_FOR(xml->attr, attr) {
7278 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01007279 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007280 break;
7281 }
7282 }
7283 assert(attr);
7284 }
Radek Krejcie534c132016-11-23 13:32:31 +01007285 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007286 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007287 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007288 iff_data = str_node;
7289 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02007290 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02007291 case UNRES_FEATURE:
7292 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
7293 ((struct lys_feature *)item)->name);
7294 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007295 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01007296 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007297 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01007298 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02007299 case UNRES_TYPE_DFLT:
Michal Vaskoba835cd2018-02-23 09:25:48 +01007300 if (*(char **)str_node) {
7301 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
Radek Krejci2e2de832016-10-13 16:12:26 +02007302 } /* else no default value in the type itself, but we are checking some restrictions against
7303 * possible default value of some base type. The failure is caused by not resolved base type,
7304 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02007305 break;
7306 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007307 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007308 break;
7309 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01007310 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007311 break;
7312 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01007313 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007314 break;
Michal Vasko7178e692016-02-12 15:58:05 +01007315 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007316 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
7317 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01007318 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02007319 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01007320 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
7321 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02007322 break;
Radek Krejcie534c132016-11-23 13:32:31 +01007323 case UNRES_EXT:
7324 extinfo = (struct unres_ext *)str_node;
7325 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7326 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7327 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007328 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007329 LOGINT(NULL);
Michal Vaskof02e3742015-08-05 16:27:02 +02007330 break;
7331 }
7332}
7333
Michal Vasko0f437062018-06-08 15:52:39 +02007334static int
7335resolve_unres_schema_types(struct unres_schema *unres, enum UNRES_ITEM types, struct ly_ctx *ctx, int forward_ref,
7336 int print_all_errors, uint32_t *resolved)
7337{
7338 uint32_t i, unres_count, res_count;
7339 int ret = 0, rc;
7340 struct ly_err_item *prev_eitem;
7341 enum int_log_opts prev_ilo;
7342 LY_ERR prev_ly_errno;
7343
7344 /* if there can be no forward references, every failure is final, so we can print it directly */
7345 if (forward_ref) {
7346 prev_ly_errno = ly_errno;
7347 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7348 }
7349
7350 do {
7351 unres_count = 0;
7352 res_count = 0;
7353
7354 for (i = 0; i < unres->count; ++i) {
7355 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7356 * if-features are resolved here to make sure that we will have all if-features for
7357 * later check of feature circular dependency */
7358 if (unres->type[i] & types) {
7359 ++unres_count;
7360 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7361 if (unres->type[i] == UNRES_EXT_FINALIZE) {
7362 /* to avoid double free */
7363 unres->type[i] = UNRES_RESOLVED;
7364 }
7365 if (!rc || (unres->type[i] == UNRES_XPATH)) {
7366 /* invalid XPath can never cause an error, only a warning */
7367 if (unres->type[i] == UNRES_LIST_UNIQ) {
7368 /* free the allocated structure */
7369 free(unres->item[i]);
7370 }
7371
7372 unres->type[i] = UNRES_RESOLVED;
7373 ++(*resolved);
7374 ++res_count;
7375 } else if ((rc == EXIT_FAILURE) && forward_ref) {
7376 /* forward reference, erase errors */
7377 ly_err_free_next(ctx, prev_eitem);
7378 } else if (print_all_errors) {
7379 /* just so that we quit the loop */
7380 ++res_count;
7381 ret = -1;
7382 } else {
Michal Vaskoffdf4ce2018-08-17 10:31:49 +02007383 if (forward_ref) {
7384 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
7385 }
Michal Vasko0f437062018-06-08 15:52:39 +02007386 return -1;
7387 }
7388 }
7389 }
7390 } while (res_count && (res_count < unres_count));
7391
7392 if (res_count < unres_count) {
7393 assert(forward_ref);
7394 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7395 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7396
7397 for (i = 0; i < unres->count; ++i) {
7398 if (unres->type[i] & types) {
7399 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7400 }
7401 }
7402 return -1;
7403 }
7404
7405 if (forward_ref) {
7406 /* restore log */
7407 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7408 ly_errno = prev_ly_errno;
7409 }
7410
7411 return ret;
7412}
7413
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007414/**
Michal Vaskobb211122015-08-19 14:03:11 +02007415 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007416 *
7417 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007418 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007419 *
Michal Vasko92b8a382015-08-19 14:03:49 +02007420 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007421 */
Michal Vaskof02e3742015-08-05 16:27:02 +02007422int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007423resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02007424{
Michal Vasko0f437062018-06-08 15:52:39 +02007425 uint32_t resolved = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007426
7427 assert(unres);
7428
Michal Vaskoe8734262016-09-29 14:12:06 +02007429 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko51054ca2015-08-12 12:20:00 +02007430
Michal Vasko0f437062018-06-08 15:52:39 +02007431 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7432 * if-features are resolved here to make sure that we will have all if-features for
7433 * later check of feature circular dependency */
7434 if (resolve_unres_schema_types(unres, UNRES_USES | UNRES_IFFEAT | UNRES_TYPE_DER | UNRES_TYPE_DER_TPDF | UNRES_TYPE_DER_TPDF
Michal Vasko6130b112020-07-02 09:28:41 +02007435 | UNRES_AUGMENT | UNRES_CHOICE_DFLT | UNRES_IDENT,
Michal Vasko0f437062018-06-08 15:52:39 +02007436 mod->ctx, 1, 0, &resolved)) {
Michal Vasko92b8a382015-08-19 14:03:49 +02007437 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007438 }
7439
Michal Vasko6130b112020-07-02 09:28:41 +02007440 if (resolve_unres_schema_types(unres, UNRES_MOD_IMPLEMENT, mod->ctx, 1, 0, &resolved)) {
7441 return -1;
7442 }
7443
Michal Vaskocab70b12020-08-20 10:16:45 +02007444 /* another batch of resolved items (UNRES_MOD_IMPLEMENT must be set again because it can be added again) */
Michal Vasko0f437062018-06-08 15:52:39 +02007445 if (resolve_unres_schema_types(unres, UNRES_TYPE_IDENTREF | UNRES_FEATURE | UNRES_TYPEDEF_DFLT | UNRES_TYPE_DFLT
Michal Vaskocab70b12020-08-20 10:16:45 +02007446 | UNRES_TYPE_LEAFREF | UNRES_LIST_KEYS | UNRES_LIST_UNIQ | UNRES_EXT | UNRES_MOD_IMPLEMENT,
7447 mod->ctx, 1, 0, &resolved)) {
Michal Vasko0f437062018-06-08 15:52:39 +02007448 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007449 }
7450
Michal Vasko0f437062018-06-08 15:52:39 +02007451 /* print xpath warnings and finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7452 if (resolve_unres_schema_types(unres, UNRES_XPATH | UNRES_EXT_FINALIZE, mod->ctx, 0, 1, &resolved)) {
7453 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007454 }
7455
Michal Vaskoe8734262016-09-29 14:12:06 +02007456 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01007457 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007458 return EXIT_SUCCESS;
7459}
7460
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007461/**
Michal Vaskobb211122015-08-19 14:03:11 +02007462 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007463 *
7464 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007465 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007466 * @param[in] item Item to resolve. Type determined by \p type.
7467 * @param[in] type Type of the unresolved item.
7468 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007469 *
Michal Vasko3767fb22016-07-21 12:10:57 +02007470 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007471 */
7472int
Radek Krejci48464ed2016-03-17 15:44:09 +01007473unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7474 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007475{
Radek Krejci54081ce2016-08-12 15:21:47 +02007476 int rc;
7477 const char *dictstr;
7478
7479 dictstr = lydict_insert(mod->ctx, str, 0);
7480 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7481
Radek Krejcid9c0ce22017-01-20 15:20:16 +01007482 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02007483 lydict_remove(mod->ctx, dictstr);
7484 }
7485 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007486}
7487
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007488/**
Michal Vaskobb211122015-08-19 14:03:11 +02007489 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007490 *
7491 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007492 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007493 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01007494 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007495 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007496 *
Radek Krejci62f7aad2017-10-26 14:53:52 +02007497 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007498 */
7499int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007500unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01007501 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007502{
Michal Vasko53b7da02018-02-13 15:28:42 +01007503 int rc;
Radek Krejci62f7aad2017-10-26 14:53:52 +02007504 uint32_t u;
Michal Vasko53b7da02018-02-13 15:28:42 +01007505 enum int_log_opts prev_ilo;
7506 struct ly_err_item *prev_eitem;
7507 LY_ERR prev_ly_errno;
Michal Vasko88c29542015-11-27 14:57:53 +01007508 struct lyxml_elem *yin;
Michal Vaskod439b2a2020-05-04 17:45:14 +02007509 struct lys_type *stype;
Michal Vasko53b7da02018-02-13 15:28:42 +01007510 struct ly_ctx *ctx = mod->ctx;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007511
Michal Vasko0f437062018-06-08 15:52:39 +02007512 assert(unres && (item || (type == UNRES_MOD_IMPLEMENT)) && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID)
7513 && (type != UNRES_WHEN) && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007514
Radek Krejci850a5de2016-11-08 14:06:40 +01007515 /* check for duplicities in unres */
7516 for (u = 0; u < unres->count; u++) {
7517 if (unres->type[u] == type && unres->item[u] == item &&
7518 unres->str_snode[u] == snode && unres->module[u] == mod) {
Radek Krejci62f7aad2017-10-26 14:53:52 +02007519 /* duplication can happen when the node contains multiple statements of the same type to check,
7520 * this can happen for example when refinement is being applied, so we just postpone the processing
7521 * and do not duplicate the information */
7522 return EXIT_FAILURE;
Radek Krejci850a5de2016-11-08 14:06:40 +01007523 }
7524 }
7525
Michal Vasko0f437062018-06-08 15:52:39 +02007526 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH) || (type == UNRES_MOD_IMPLEMENT)) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02007527 /* extension finalization is not even tried when adding the item into the inres list,
Michal Vasko0f437062018-06-08 15:52:39 +02007528 * xpath is not tried because it would hide some potential warnings,
7529 * implementing module must be deferred because some other nodes can be added that will need to be traversed
7530 * and their targets made implemented */
Radek Krejcic293bac2017-02-27 11:25:28 +01007531 rc = EXIT_FAILURE;
7532 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007533 prev_ly_errno = ly_errno;
7534 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007535
Michal Vasko53b7da02018-02-13 15:28:42 +01007536 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01007537 if (rc != EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007538 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7539 if (rc != -1) {
Michal Vaskod439b2a2020-05-04 17:45:14 +02007540 /* print warnings here so that they are actually printed */
7541 if ((type == UNRES_TYPE_DER_TPDF) || (type == UNRES_TYPE_DER)) {
7542 stype = item;
7543 if (stype->der->module && (((stype->base == LY_TYPE_LEAFREF)
7544 && (stype->info.lref.req != stype->der->type.info.lref.req)) || ((stype->base == LY_TYPE_INST)
7545 && (stype->info.inst.req != stype->der->type.info.inst.req)))) {
7546 if (type == UNRES_TYPE_DER_TPDF) {
7547 /* typedef */
7548 LOGWRN(ctx, "Derived typedef \"%s\" is changing the \"require-instance\" property, "
7549 "which is discouraged.", stype->parent->name);
7550 } else {
7551 /* leaf */
7552 LOGWRN(ctx, "Node \"%s\" type is changing the \"require-instance\" property, "
7553 "which is discouraged.", snode->name);
7554 }
7555 }
7556 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007557 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007558 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007559
Radek Krejci80056d52017-01-05 13:13:33 +01007560 if (type == UNRES_LIST_UNIQ) {
7561 /* free the allocated structure */
7562 free(item);
7563 } else if (rc == -1 && type == UNRES_IFFEAT) {
7564 /* free the allocated resources */
7565 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007566 }
Radek Krejci80056d52017-01-05 13:13:33 +01007567 return rc;
7568 } else {
7569 /* erase info about validation errors */
Michal Vasko53b7da02018-02-13 15:28:42 +01007570 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7571 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007572 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007573
Radek Krejci80056d52017-01-05 13:13:33 +01007574 print_unres_schema_item_fail(item, type, snode);
7575
7576 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7577 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7578 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7579 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7580 lyxml_unlink_elem(mod->ctx, yin, 1);
7581 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7582 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007583 }
Michal Vasko88c29542015-11-27 14:57:53 +01007584 }
7585
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007586 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007587 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Michal Vasko53b7da02018-02-13 15:28:42 +01007588 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007589 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007590 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007591 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007592 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007593 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko53b7da02018-02-13 15:28:42 +01007594 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007595 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007596 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01007597 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007598 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007599
Michal Vasko3767fb22016-07-21 12:10:57 +02007600 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007601}
7602
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007603/**
Michal Vaskobb211122015-08-19 14:03:11 +02007604 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007605 *
7606 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007607 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007608 * @param[in] item Old item to be resolved.
7609 * @param[in] type Type of the old unresolved item.
7610 * @param[in] new_item New item to use in the duplicate.
7611 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007612 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007613 */
Michal Vaskodad19402015-08-06 09:51:53 +02007614int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007615unres_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 +02007616{
7617 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007618 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007619 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007620
Michal Vaskocf024702015-10-08 15:01:42 +02007621 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007622
Radek Krejcid09d1a52016-08-11 14:05:45 +02007623 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7624 if (type == UNRES_LIST_UNIQ) {
7625 aux_uniq.list = item;
7626 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7627 item = &aux_uniq;
7628 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007629 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007630
7631 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007632 if (type == UNRES_LIST_UNIQ) {
7633 free(new_item);
7634 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007635 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007636 }
7637
Radek Krejcic79c6b12016-07-26 15:11:49 +02007638 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007639 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007640 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007641 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007642 return -1;
7643 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007644 } else if (type == UNRES_IFFEAT) {
7645 /* duplicate unres_iffeature_data */
7646 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01007647 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007648 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7649 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
Frank Rimplerdddb3212019-06-11 12:28:38 +00007650 iff_data->infeature = ((struct unres_iffeat_data *)unres->str_snode[i])->infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007651 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007652 LOGINT(mod->ctx);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007653 return -1;
7654 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007655 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007656 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007657 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007658 return -1;
7659 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007660 }
Michal Vaskodad19402015-08-06 09:51:53 +02007661
7662 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007663}
7664
Michal Vaskof02e3742015-08-05 16:27:02 +02007665/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007666int
Michal Vasko878e38d2016-09-05 12:17:53 +02007667unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007668{
Michal Vasko878e38d2016-09-05 12:17:53 +02007669 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007670 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007671
Michal Vaskoc643f712018-09-14 08:26:13 +02007672 if (!unres->count) {
7673 return -1;
7674 }
7675
Radek Krejciddddd0d2017-01-20 15:20:46 +01007676 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007677 i = start_on_backwards;
7678 } else {
7679 i = unres->count - 1;
7680 }
7681 for (; i > -1; i--) {
7682 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007683 continue;
7684 }
7685 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007686 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007687 break;
7688 }
7689 } else {
Соколов Пётр0d921ef2019-01-23 10:13:50 +03007690 aux_uniq1 = (struct unres_list_uniq *)unres->item[i];
Radek Krejcid09d1a52016-08-11 14:05:45 +02007691 aux_uniq2 = (struct unres_list_uniq *)item;
7692 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007693 break;
7694 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007695 }
7696 }
7697
Michal Vasko878e38d2016-09-05 12:17:53 +02007698 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007699}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007700
Michal Vaskoede9c472016-06-07 09:38:15 +02007701static void
7702unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7703{
7704 struct lyxml_elem *yin;
7705 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007706 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007707
7708 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007709 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007710 case UNRES_TYPE_DER:
7711 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7712 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7713 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007714 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007715 lydict_remove(ctx, yang->name);
7716 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007717 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7718 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7719 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007720 } else {
7721 lyxml_free(ctx, yin);
7722 }
7723 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007724 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007725 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7726 lydict_remove(ctx, iff_data->fname);
7727 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007728 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007729 case UNRES_IDENT:
7730 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007731 case UNRES_CHOICE_DFLT:
7732 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007733 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7734 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007735 case UNRES_LIST_UNIQ:
7736 free(unres->item[i]);
7737 break;
PavolVicanc1807262017-01-31 18:00:27 +01007738 case UNRES_EXT:
7739 free(unres->str_snode[i]);
7740 break;
PavolVicanfcc98762017-09-01 15:51:39 +02007741 case UNRES_EXT_FINALIZE:
7742 free(unres->str_snode[i]);
Michal Vaskoede9c472016-06-07 09:38:15 +02007743 default:
7744 break;
7745 }
7746 unres->type[i] = UNRES_RESOLVED;
7747}
7748
Michal Vasko88c29542015-11-27 14:57:53 +01007749void
Michal Vasko44ab1462017-05-18 13:18:36 +02007750unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007751{
7752 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007753 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007754
Radek Krejcic071c542016-01-27 14:57:51 +01007755 if (!unres || !(*unres)) {
7756 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007757 }
7758
Michal Vasko44ab1462017-05-18 13:18:36 +02007759 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007760
7761 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007762 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007763 if ((*unres)->type[i] != UNRES_RESOLVED) {
7764 unresolved++;
7765 }
7766 continue;
7767 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007768
7769 /* free heap memory for the specific item */
7770 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007771 }
7772
Michal Vaskoede9c472016-06-07 09:38:15 +02007773 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007774 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007775 free((*unres)->item);
7776 free((*unres)->type);
7777 free((*unres)->str_snode);
7778 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007779 free((*unres));
7780 (*unres) = NULL;
7781 }
Michal Vasko88c29542015-11-27 14:57:53 +01007782}
7783
Michal Vaskoff690e72017-08-03 14:25:07 +02007784/* check whether instance-identifier points outside its data subtree (for operation it is any node
7785 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007786static int
7787check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7788{
Michal Vaskoff690e72017-08-03 14:25:07 +02007789 const struct lys_node *op_node, *first_node;
Michal Vasko53b7da02018-02-13 15:28:42 +01007790 enum int_log_opts prev_ilo;
Michal Vasko2e80aff2018-12-07 08:41:07 +01007791 char *buf, *tmp;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007792
Radek Krejci034cb102017-08-01 15:45:13 +02007793 if (!json_instid || !json_instid[0]) {
7794 /* no/empty value */
7795 return 0;
7796 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007797
7798 for (op_node = lys_parent(sleaf);
7799 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7800 op_node = lys_parent(op_node));
7801
7802 if (op_node && lys_parent(op_node)) {
7803 /* nested operation - any absolute path is external */
7804 return 1;
7805 }
7806
7807 /* get the first node from the instid */
Michal Vasko2e80aff2018-12-07 08:41:07 +01007808 tmp = strchr(json_instid + 1, '/');
Michal Vasko299aef12018-12-18 13:13:55 +01007809 buf = strndup(json_instid, tmp ? (size_t)(tmp - json_instid) : strlen(json_instid));
Michal Vasko3cfa3182017-01-17 10:00:58 +01007810 if (!buf) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007811 /* so that we do not have to bother with logging, say it is not external */
7812 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007813 }
7814
Michal Vaskoff690e72017-08-03 14:25:07 +02007815 /* find the first schema node, do not log */
Michal Vasko53b7da02018-02-13 15:28:42 +01007816 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoff690e72017-08-03 14:25:07 +02007817 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
Michal Vasko53b7da02018-02-13 15:28:42 +01007818 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007819
Michal Vasko53b7da02018-02-13 15:28:42 +01007820 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007821 if (!first_node) {
Michal Vasko299aef12018-12-18 13:13:55 +01007822 /* unknown path, say it is external */
7823 return 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007824 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007825
7826 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7827
Michal Vasko299aef12018-12-18 13:13:55 +01007828 if (op_node) {
7829 if (op_node != first_node) {
7830 /* it is a top-level operation, so we're good if it points somewhere inside it */
7831 return 1;
7832 }
7833 } else {
7834 if (lys_node_module(sleaf) != lys_node_module(first_node)) {
7835 /* modules differ */
7836 return 1;
7837 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007838 }
7839
Michal Vasko299aef12018-12-18 13:13:55 +01007840 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007841}
7842
Michal Vasko436d13f2020-02-25 14:31:00 +01007843int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007844resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7845{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007846 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007847 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007848 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007849 struct lyd_node *root, *node;
Radek Krejcidaa547a2017-09-22 15:56:27 +02007850 const char *model = NULL, *name;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007851 char *str;
7852 int mod_len, name_len, has_predicate;
7853 struct unres_data node_match;
7854
7855 memset(&node_match, 0, sizeof node_match);
7856 *ret = NULL;
7857
7858 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007859 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007860 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007861 if (root->prev) {
7862 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007863 }
7864
7865 /* search for the instance node */
7866 while (path[i]) {
7867 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7868 if (j <= 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007869 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007870 goto error;
7871 }
7872 i += j;
7873
Michal Vasko1b6ca962017-08-03 14:23:09 +02007874 if (model) {
7875 str = strndup(model, mod_len);
7876 if (!str) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007877 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007878 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007879 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02007880 mod = ly_ctx_get_module(ctx, str, NULL, 1);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007881 if (ctx->data_clb) {
7882 if (!mod) {
7883 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7884 } else if (!mod->implemented) {
7885 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7886 }
7887 }
7888 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007889
Michal Vasko1b6ca962017-08-03 14:23:09 +02007890 if (!mod || !mod->implemented || mod->disabled) {
7891 break;
7892 }
7893 } else if (!prev_mod) {
7894 /* first iteration and we are missing module name */
Michal Vaskoaf8ec362018-03-28 09:08:09 +02007895 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
7896 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
Michal Vasko1b6ca962017-08-03 14:23:09 +02007897 goto error;
7898 } else {
7899 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007900 }
7901
Radek Krejci2c822ed2017-08-03 14:23:36 +02007902 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007903 /* no instance exists */
7904 break;
7905 }
7906
7907 if (has_predicate) {
7908 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcidaa547a2017-09-22 15:56:27 +02007909 parsed = j = 0;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007910 /* index of the current node (for lists with position predicates) */
7911 cur_idx = 1;
7912 while (j < (signed)node_match.count) {
7913 node = node_match.node[j];
7914 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7915 if (parsed < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007916 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007917 goto error;
7918 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007919
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007920 if (!node) {
7921 /* current node does not satisfy the predicate */
7922 unres_data_del(&node_match, j);
7923 } else {
7924 ++j;
7925 }
7926 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007927 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007928
7929 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007930 } else if (node_match.count) {
7931 /* check that we are not addressing lists */
7932 for (j = 0; (unsigned)j < node_match.count; ++j) {
7933 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7934 unres_data_del(&node_match, j--);
7935 }
7936 }
7937 if (!node_match.count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007938 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007939 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007940 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007941
7942 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007943 }
7944
7945 if (!node_match.count) {
7946 /* no instance exists */
7947 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007948 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007949 return EXIT_FAILURE;
7950 }
7951 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7952 return EXIT_SUCCESS;
7953 } else if (node_match.count > 1) {
7954 /* instance identifier must resolve to a single node */
Michal Vasko53b7da02018-02-13 15:28:42 +01007955 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007956 goto error;
7957 } else {
7958 /* we have required result, remember it and cleanup */
7959 *ret = node_match.node[0];
7960 free(node_match.node);
7961 return EXIT_SUCCESS;
7962 }
7963
7964error:
7965 /* cleanup */
7966 free(node_match.node);
7967 return -1;
7968}
7969
Michal Vasko436d13f2020-02-25 14:31:00 +01007970int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007971resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007972{
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007973 struct lyxp_set xp_set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007974 uint32_t i;
7975
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007976 memset(&xp_set, 0, sizeof xp_set);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007977 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007978
Michal Vaskoca16cb32017-07-10 11:50:33 +02007979 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007980 if (lyxp_eval(path, (struct lyd_node *)leaf, LYXP_NODE_ELEM, lyd_node_module((struct lyd_node *)leaf), &xp_set, 0) != EXIT_SUCCESS) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007981 return -1;
7982 }
7983
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007984 if (xp_set.type == LYXP_SET_NODE_SET) {
7985 for (i = 0; i < xp_set.used; ++i) {
7986 if ((xp_set.val.nodes[i].type != LYXP_NODE_ELEM) || !(xp_set.val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7987 continue;
7988 }
Michal Vaskoca16cb32017-07-10 11:50:33 +02007989
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007990 /* not that the value is already in canonical form since the parsers does the conversion,
7991 * so we can simply compare just the values */
7992 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)xp_set.val.nodes[i].node)->value_str, 1)) {
7993 /* we have the match */
7994 *ret = xp_set.val.nodes[i].node;
7995 break;
7996 }
Radek Krejci7de36cf2016-09-12 16:18:50 +02007997 }
7998 }
7999
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02008000 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, (struct lyd_node *)leaf, NULL, 0);
Radek Krejci7de36cf2016-09-12 16:18:50 +02008001
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008002 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02008003 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008004 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008005 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02008006 return EXIT_FAILURE;
8007 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008008 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 +02008009 }
8010 }
8011
8012 return EXIT_SUCCESS;
8013}
8014
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008015/* 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 +01008016int
8017resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
8018 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02008019{
Michal Vasko53b7da02018-02-13 15:28:42 +01008020 struct ly_ctx *ctx = leaf->schema->module->ctx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008021 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008022 struct lyd_node *ret;
Michal Vasko53b7da02018-02-13 15:28:42 +01008023 enum int_log_opts prev_ilo;
8024 int found, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008025 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02008026
8027 assert(type->base == LY_TYPE_UNION);
8028
Michal Vasko101658e2018-06-05 15:05:54 +02008029 if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LY_VALUE_UNRES))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008030 /* either NULL or instid previously converted to JSON */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01008031 json_val = lydict_insert(ctx, leaf->value.string, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008032 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01008033
Michal Vaskofd6c6502017-01-06 12:15:41 +01008034 if (store) {
Michal Vasko7ba37442018-11-06 08:59:27 +01008035 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
Michal Vaskod3dd15d2019-01-23 14:06:58 +01008036 leaf->value_str, NULL, NULL, NULL);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008037 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01008038 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008039
8040 /* 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 +01008041 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008042
8043 t = NULL;
8044 found = 0;
8045 while ((t = lyp_get_next_union_type(type, t, &found))) {
8046 found = 0;
8047
8048 switch (t->base) {
8049 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01008050 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
8051 req_inst = -1;
8052 } else {
8053 req_inst = t->info.lref.req;
8054 }
8055
8056 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01008057 if (store) {
8058 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
8059 /* valid resolved */
8060 leaf->value.leafref = ret;
8061 leaf->value_type = LY_TYPE_LEAFREF;
8062 } else {
8063 /* valid unresolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01008064 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko0abb1bc2020-02-25 15:47:10 +01008065 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01008066 return -1;
8067 }
Michal Vasko53b7da02018-02-13 15:28:42 +01008068 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008069 }
8070 }
8071
8072 success = 1;
8073 }
8074 break;
8075 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01008076 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
8077 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
8078 req_inst = -1;
8079 } else {
8080 req_inst = t->info.inst.req;
8081 }
8082
Michal Vaskod3a03112017-01-23 09:56:02 +01008083 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01008084 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008085 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01008086 /* valid resolved */
8087 leaf->value.instance = ret;
8088 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008089
Michal Vaskofd6c6502017-01-06 12:15:41 +01008090 if (json_val) {
8091 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
8092 leaf->value_str = json_val;
8093 json_val = NULL;
8094 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008095 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01008096 /* valid unresolved */
8097 if (json_val) {
8098 /* put the JSON val back */
8099 leaf->value.string = json_val;
8100 json_val = NULL;
8101 } else {
8102 leaf->value.instance = NULL;
8103 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02008104 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02008105 leaf->value_flags |= LY_VALUE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008106 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008107 }
8108
8109 success = 1;
8110 }
8111 break;
8112 default:
Michal Vasko0abb1bc2020-02-25 15:47:10 +01008113 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008114 success = 1;
8115 }
8116 break;
8117 }
8118
8119 if (success) {
8120 break;
8121 }
8122
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008123 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01008124 if (store) {
Michal Vaskod3dd15d2019-01-23 14:06:58 +01008125 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t, leaf->value_str, NULL, NULL, NULL);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008126 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008127 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008128 }
8129
8130 /* turn logging back on */
Michal Vasko53b7da02018-02-13 15:28:42 +01008131 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008132
8133 if (json_val) {
8134 if (!success) {
8135 /* put the value back for now */
8136 assert(leaf->value_type == LY_TYPE_UNION);
8137 leaf->value.string = json_val;
8138 } else {
8139 /* value was ultimately useless, but we could not have known */
8140 lydict_remove(leaf->schema->module->ctx, json_val);
8141 }
8142 }
8143
Michal Vaskofd6c6502017-01-06 12:15:41 +01008144 if (success) {
8145 if (resolved_type) {
8146 *resolved_type = t;
8147 }
8148 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008149 /* not found and it is required */
Michal Vasko53b7da02018-02-13 15:28:42 +01008150 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02008151 return EXIT_FAILURE;
8152 }
8153
8154 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008155
Radek Krejci9b6aad22016-09-20 15:55:51 +02008156}
8157
Michal Vasko8bcdf292015-08-19 14:04:43 +02008158/**
8159 * @brief Resolve a single unres data item. Logs directly.
8160 *
Michal Vaskocf024702015-10-08 15:01:42 +02008161 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02008162 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01008163 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008164 *
8165 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
8166 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02008167int
Michal Vasko0b963112017-08-11 12:45:36 +02008168resolve_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 +02008169{
Michal Vasko3cfa3182017-01-17 10:00:58 +01008170 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02008171 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008172 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008173 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008174
Michal Vasko83a6c462015-10-08 16:43:53 +02008175 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02008176 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008177
Michal Vaskocf024702015-10-08 15:01:42 +02008178 switch (type) {
8179 case UNRES_LEAFREF:
8180 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vasko35689942019-09-10 10:33:33 +02008181 if (ignore_fail) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008182 req_inst = -1;
8183 } else {
8184 req_inst = sleaf->type.info.lref.req;
8185 }
Michal Vasko35689942019-09-10 10:33:33 +02008186 if ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2)) {
8187 /* do not even try to resolve */
8188 rc = 0;
8189 ret = NULL;
8190 } else {
8191 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
8192 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008193 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01008194 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008195 /* valid resolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02008196 if (leaf->value_type == LY_TYPE_BITS) {
Michal Vasko1c8567a2017-01-05 13:42:27 +01008197 free(leaf->value.bit);
8198 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008199 leaf->value.leafref = ret;
8200 leaf->value_type = LY_TYPE_LEAFREF;
Michal Vasko101658e2018-06-05 15:05:54 +02008201 leaf->value_flags &= ~LY_VALUE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008202 } else {
8203 /* valid unresolved */
Michal Vasko101658e2018-06-05 15:05:54 +02008204 if (!(leaf->value_flags & LY_VALUE_UNRES)) {
Michal Vasko0abb1bc2020-02-25 15:47:10 +01008205 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008206 return -1;
8207 }
8208 }
8209 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008210 } else {
8211 return rc;
8212 }
8213 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008214
Michal Vaskocf024702015-10-08 15:01:42 +02008215 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02008216 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01008217 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
8218 if (ext_dep == -1) {
8219 return -1;
8220 }
8221
Michal Vasko35689942019-09-10 10:33:33 +02008222 if (ignore_fail) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008223 req_inst = -1;
8224 } else {
8225 req_inst = sleaf->type.info.inst.req;
8226 }
Michal Vasko35689942019-09-10 10:33:33 +02008227 if (ext_dep && (ignore_fail == 2)) {
8228 /* do not even try to resolve */
8229 rc = 0;
8230 ret = NULL;
8231 } else {
8232 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
8233 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008234 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008235 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008236 /* valid resolved */
8237 leaf->value.instance = ret;
8238 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02008239 leaf->value_flags &= ~LY_VALUE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008240 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008241 /* valid unresolved */
8242 leaf->value.instance = NULL;
Michal Vasko70bf8e52018-03-26 11:32:33 +02008243 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02008244 leaf->value_flags |= LY_VALUE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008245 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008246 } else {
8247 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008248 }
Michal Vaskocf024702015-10-08 15:01:42 +02008249 break;
8250
Radek Krejci7de36cf2016-09-12 16:18:50 +02008251 case UNRES_UNION:
8252 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008253 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02008254
Michal Vaskocf024702015-10-08 15:01:42 +02008255 case UNRES_WHEN:
Michal Vasko0b963112017-08-11 12:45:36 +02008256 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02008257 return rc;
8258 }
8259 break;
8260
Michal Vaskobf19d252015-10-08 15:39:17 +02008261 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008262 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02008263 return rc;
8264 }
8265 break;
8266
8267 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008268 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02008269 return rc;
8270 }
8271 break;
8272
Michal Vasko185b5272018-09-13 14:26:12 +02008273 case UNRES_UNIQ_LEAVES:
8274 if (lyv_data_unique(node)) {
8275 return -1;
8276 }
8277 break;
8278
Michal Vaskocf024702015-10-08 15:01:42 +02008279 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01008280 LOGINT(NULL);
Michal Vasko8bcdf292015-08-19 14:04:43 +02008281 return -1;
8282 }
8283
8284 return EXIT_SUCCESS;
8285}
8286
8287/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01008288 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02008289 *
8290 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02008291 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008292 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01008293 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008294 */
8295int
Radek Krejci0b7704f2016-03-18 12:16:14 +01008296unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02008297{
Radek Krejci03b71f72016-03-16 11:10:09 +01008298 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02008299 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vasko185b5272018-09-13 14:26:12 +02008300 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_UNIQ_LEAVES));
Michal Vasko8bcdf292015-08-19 14:04:43 +02008301
Radek Krejci03b71f72016-03-16 11:10:09 +01008302 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01008303 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01008304 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008305 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01008306 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01008307 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008308 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008309
Michal Vasko53b7da02018-02-13 15:28:42 +01008310 return 0;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008311}
8312
Michal Vasko20555d82018-12-12 16:30:50 +01008313static void
8314resolve_unres_data_autodel_diff(struct unres_data *unres, uint32_t unres_i)
8315{
8316 struct lyd_node *next, *child, *parent;
8317 uint32_t i;
8318
8319 for (i = 0; i < unres->diff_idx; ++i) {
8320 if (unres->diff->type[i] == LYD_DIFF_DELETED) {
8321 /* only leaf(-list) default could be removed and there is nothing to be checked in that case */
8322 continue;
8323 }
8324
8325 if (unres->diff->second[i] == unres->node[unres_i]) {
8326 /* 1) default value was supposed to be created, but is disabled by when
8327 * -> remove it from diff altogether
8328 */
8329 unres_data_diff_rem(unres, i);
8330 /* if diff type is CREATED, the value was just a pointer, it can be freed normally (unlike in 4) */
8331 return;
8332 } else {
8333 parent = unres->diff->second[i]->parent;
8334 while (parent && (parent != unres->node[unres_i])) {
8335 parent = parent->parent;
8336 }
8337 if (parent) {
8338 /* 2) default value was supposed to be created but is disabled by when in some parent
8339 * -> remove this default subtree and add the rest into diff as deleted instead in 4)
8340 */
8341 unres_data_diff_rem(unres, i);
8342 break;
8343 }
8344
Michal Vaskod6162b72019-11-13 14:04:38 +01008345 LY_TREE_DFS_BEGIN(unres->diff->second[i], next, child) {
Michal Vasko20555d82018-12-12 16:30:50 +01008346 if (child == unres->node[unres_i]) {
8347 /* 3) some default child of a default value was supposed to be created but has false when
8348 * -> the subtree will be freed later and automatically disconnected from the diff parent node
8349 */
8350 return;
8351 }
8352
Michal Vaskod6162b72019-11-13 14:04:38 +01008353 LY_TREE_DFS_END(unres->diff->second[i], next, child);
Michal Vasko20555d82018-12-12 16:30:50 +01008354 }
8355 }
8356 }
8357
8358 /* 4) it does not overlap with created default values in any way
8359 * -> just add it into diff as deleted
8360 */
8361 unres_data_diff_new(unres, unres->node[unres_i], unres->node[unres_i]->parent, 0);
8362 lyd_unlink(unres->node[unres_i]);
8363
8364 /* should not be freed anymore */
8365 unres->node[unres_i] = NULL;
8366}
8367
Michal Vasko8bcdf292015-08-19 14:04:43 +02008368/**
8369 * @brief Resolve every unres data item in the structure. Logs directly.
8370 *
Michal Vasko660582a2018-03-19 10:10:08 +01008371 * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
8372 * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
8373 * non-presence containers may need to be deleted).
Radek Krejci082c84f2016-10-17 16:33:06 +02008374 *
Michal Vaskobbc43b12018-10-12 09:22:00 +02008375 * If options includes #LYD_OPT_WHENAUTODEL, the non-default nodes with false when conditions are auto-deleted.
Radek Krejci082c84f2016-10-17 16:33:06 +02008376 *
Michal Vasko53b7da02018-02-13 15:28:42 +01008377 * @param[in] ctx Context used.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008378 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02008379 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
8380 * @param[in] options Data options as described above.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008381 *
8382 * @return EXIT_SUCCESS on success, -1 on error.
8383 */
8384int
Michal Vasko53b7da02018-02-13 15:28:42 +01008385resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
Michal Vasko8bcdf292015-08-19 14:04:43 +02008386{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008387 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko8af82202018-11-14 11:21:01 +01008388 uint8_t prev_when_status;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008389 int rc, progress, ignore_fail;
Michal Vasko53b7da02018-02-13 15:28:42 +01008390 enum int_log_opts prev_ilo;
8391 struct ly_err_item *prev_eitem;
mohitarora2489837dc2018-05-01 15:09:36 +05308392 LY_ERR prev_ly_errno = ly_errno;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008393 struct lyd_node *parent;
Michal Vasko0b963112017-08-11 12:45:36 +02008394 struct lys_when *when;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008395
Radek Krejci082c84f2016-10-17 16:33:06 +02008396 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01008397 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01008398
8399 if (!unres->count) {
8400 return EXIT_SUCCESS;
8401 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02008402
Michal Vasko7fa93142018-03-19 09:59:10 +01008403 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008404 ignore_fail = 1;
8405 } else if (options & LYD_OPT_NOEXTDEPS) {
8406 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008407 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008408 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008409 }
8410
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008411 LOGVRB("Resolving unresolved data nodes and their constraints...");
Michal Vasko7fa93142018-03-19 09:59:10 +01008412 if (!ignore_fail) {
8413 /* remember logging state only if errors are generated and valid */
Michal Vasko7fa93142018-03-19 09:59:10 +01008414 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8415 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008416
Michal Vasko7fa93142018-03-19 09:59:10 +01008417 /*
8418 * when-stmt first
8419 */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008420 first = 1;
8421 stmt_count = 0;
8422 resolved = 0;
8423 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01008424 do {
Michal Vasko7fa93142018-03-19 09:59:10 +01008425 if (!ignore_fail) {
8426 ly_err_free_next(ctx, prev_eitem);
8427 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008428 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02008429 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008430 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008431 continue;
8432 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008433 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008434 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008435 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008436 }
8437
8438 /* resolve when condition only when all parent when conditions are already resolved */
8439 for (parent = unres->node[i]->parent;
8440 parent && LYD_WHEN_DONE(parent->when_status);
8441 parent = parent->parent) {
8442 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8443 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02008444 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01008445 */
8446 unres->node[i]->when_status |= LYD_WHEN_FALSE;
8447 unres->type[i] = UNRES_RESOLVED;
8448 resolved++;
8449 break;
8450 }
8451 }
8452 if (parent) {
8453 continue;
8454 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008455
Michal Vasko8af82202018-11-14 11:21:01 +01008456 prev_when_status = unres->node[i]->when_status;
Michal Vasko0b963112017-08-11 12:45:36 +02008457 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01008458 if (!rc) {
Michal Vasko8af82202018-11-14 11:21:01 +01008459 /* finish with error/delete the node only if when was changed from true to false, an external
8460 * dependency was not required, or it was not provided (the flag would not be passed down otherwise,
8461 * checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02008462 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vaskoc04173b2018-03-09 10:43:22 +01008463 && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
Michal Vasko8af82202018-11-14 11:21:01 +01008464 if ((!(prev_when_status & LYD_WHEN_TRUE) || !(options & LYD_OPT_WHENAUTODEL)) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01008465 /* false when condition */
Michal Vasko53b7da02018-02-13 15:28:42 +01008466 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008467 } /* follows else */
8468
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008469 /* auto-delete */
Michal Vasko8af82202018-11-14 11:21:01 +01008470 LOGVRB("Auto-deleting node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008471
Michal Vasko56c14282019-11-12 10:02:27 +01008472 /* do not delete yet, the subtree can contain another nodes stored in the unres list */
Radek Krejci0c0086a2016-03-24 15:20:28 +01008473 /* if it has parent non-presence containers that would be empty, we should actually
8474 * remove the container
8475 */
Radek Krejci2537fd32016-09-07 16:22:41 +02008476 for (parent = unres->node[i];
8477 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8478 parent = parent->parent) {
8479 if (((struct lys_node_container *)parent->parent->schema)->presence) {
8480 /* presence container */
8481 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008482 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008483 if (parent->next || parent->prev != parent) {
8484 /* non empty (the child we are in and we are going to remove is not the only child) */
8485 break;
8486 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008487 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008488 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008489
Radek Krejci0c0086a2016-03-24 15:20:28 +01008490 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008491 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01008492 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008493
Radek Krejci0b7704f2016-03-18 12:16:14 +01008494 unres->type[i] = UNRES_DELETE;
8495 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01008496
8497 /* update the rest of unres items */
8498 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01008499 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01008500 continue;
8501 }
8502
8503 /* test if the node is in subtree to be deleted */
8504 for (parent = unres->node[j]; parent; parent = parent->parent) {
8505 if (parent == unres->node[i]) {
8506 /* yes, it is */
8507 unres->type[j] = UNRES_RESOLVED;
8508 resolved++;
8509 break;
8510 }
8511 }
8512 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008513 } else {
8514 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01008515 }
Michal Vasko7fa93142018-03-19 09:59:10 +01008516 if (!ignore_fail) {
8517 ly_err_free_next(ctx, prev_eitem);
8518 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008519 resolved++;
8520 progress = 1;
8521 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008522 goto error;
Radek Krejci2467a492016-10-24 15:16:59 +02008523 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01008524 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008525 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008526 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01008527
Radek Krejci0b7704f2016-03-18 12:16:14 +01008528 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008529 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008530 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008531 }
8532
8533 for (i = 0; del_items && i < unres->count; i++) {
8534 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8535 if (unres->type[i] != UNRES_DELETE) {
8536 continue;
8537 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008538 if (!unres->node[i]) {
8539 unres->type[i] = UNRES_RESOLVED;
8540 del_items--;
8541 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008542 }
8543
Michal Vasko20555d82018-12-12 16:30:50 +01008544 if (unres->store_diff) {
8545 resolve_unres_data_autodel_diff(unres, i);
8546 }
8547
Radek Krejci0b7704f2016-03-18 12:16:14 +01008548 /* really remove the complete subtree */
8549 lyd_free(unres->node[i]);
8550 unres->type[i] = UNRES_RESOLVED;
8551 del_items--;
8552 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008553
Michal Vasko7fa93142018-03-19 09:59:10 +01008554 /*
8555 * now leafrefs
8556 */
8557 if (options & LYD_OPT_TRUSTED) {
8558 /* we want to attempt to resolve leafrefs */
8559 assert(!ignore_fail);
8560 ignore_fail = 1;
8561
8562 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8563 ly_errno = prev_ly_errno;
8564 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008565 first = 1;
8566 stmt_count = 0;
8567 resolved = 0;
8568 do {
8569 progress = 0;
8570 for (i = 0; i < unres->count; i++) {
8571 if (unres->type[i] != UNRES_LEAFREF) {
8572 continue;
8573 }
8574 if (first) {
8575 /* count leafref nodes in unres list */
8576 stmt_count++;
8577 }
8578
Michal Vasko0b963112017-08-11 12:45:36 +02008579 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008580 if (!rc) {
8581 unres->type[i] = UNRES_RESOLVED;
Michal Vasko7fa93142018-03-19 09:59:10 +01008582 if (!ignore_fail) {
8583 ly_err_free_next(ctx, prev_eitem);
8584 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008585 resolved++;
8586 progress = 1;
8587 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008588 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008589 } /* else forward reference */
8590 }
8591 first = 0;
8592 } while (progress && resolved < stmt_count);
8593
8594 /* do we have some unresolved leafrefs? */
8595 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008596 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008597 }
8598
Michal Vasko7fa93142018-03-19 09:59:10 +01008599 if (!ignore_fail) {
8600 /* log normally now, throw away irrelevant errors */
8601 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8602 ly_errno = prev_ly_errno;
8603 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008604
Michal Vasko7fa93142018-03-19 09:59:10 +01008605 /*
8606 * rest
8607 */
Michal Vasko8bcdf292015-08-19 14:04:43 +02008608 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008609 if (unres->type[i] == UNRES_RESOLVED) {
8610 continue;
8611 }
Radek Krejci082c84f2016-10-17 16:33:06 +02008612 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01008613
Michal Vasko0b963112017-08-11 12:45:36 +02008614 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008615 if (rc) {
8616 /* since when was already resolved, a forward reference is an error */
Michal Vasko8bcdf292015-08-19 14:04:43 +02008617 return -1;
8618 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008619
8620 unres->type[i] = UNRES_RESOLVED;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008621 }
8622
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008623 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01008624 unres->count = 0;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008625 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01008626
8627error:
Michal Vasko7fa93142018-03-19 09:59:10 +01008628 if (!ignore_fail) {
8629 /* print all the new errors */
8630 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8631 /* do not restore ly_errno, it was udpated properly */
8632 }
Michal Vasko53b7da02018-02-13 15:28:42 +01008633 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008634}