blob: 0b4cd030176a9554d1565772fcf75f7320d25f83 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
Michal Vasko53b7da02018-02-13 15:28:42 +01006 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
Michal Vasko730dfdf2015-08-11 14:48:05 +02007 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Michal Vasko6c810702018-03-14 16:23:21 +010030#include "hash_table.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
Radek Krejcie534c132016-11-23 13:32:31 +010032#include "extensions.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020033
Michal Vasko2d44ee02018-05-18 09:38:51 +020034/* internal parsed predicate structure */
35struct parsed_pred {
36 const struct lys_node *schema;
37 int len;
38 struct {
39 const char *mod_name;
40 int mod_name_len;
41 const char *name;
42 int nam_len;
43 const char *value;
44 int val_len;
45 } *pred;
46};
47
Michal Vaskod24dd012016-09-30 12:20:22 +020048int
49parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020050{
51 const char *ptr;
52 int minus = 0;
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020053 int64_t ret = 0, prev_ret;
Radek Krejcibf47a822016-11-04 10:06:08 +010054 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020055
56 ptr = *str_num;
57
58 if (ptr[0] == '-') {
59 minus = 1;
60 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010061 } else if (ptr[0] == '+') {
62 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020063 }
64
Michal Vaskod24dd012016-09-30 12:20:22 +020065 if (!isdigit(ptr[0])) {
66 /* there must be at least one */
67 return 1;
68 }
69
Michal Vasko4d1f0482016-09-19 14:35:06 +020070 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
71 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020072 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020073 }
74
75 if (ptr[0] == '.') {
76 if (ptr[1] == '.') {
77 /* it's the next interval */
78 break;
79 }
80 ++str_dig;
81 } else {
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020082 prev_ret = ret;
83 if (minus) {
84 ret = ret * 10 - (ptr[0] - '0');
85 if (ret > prev_ret) {
86 return 1;
87 }
88 } else {
89 ret = ret * 10 + (ptr[0] - '0');
90 if (ret < prev_ret) {
91 return 1;
92 }
93 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020094 if (str_dig > -1) {
95 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010096 if (ptr[0] == '0') {
97 /* possibly trailing zero */
98 trailing_zeros++;
99 } else {
100 trailing_zeros = 0;
101 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200102 }
103 ++str_exp;
104 }
105 }
Michal Vaskod24dd012016-09-30 12:20:22 +0200106 if (str_dig == 0) {
107 /* no digits after '.' */
108 return 1;
109 } else if (str_dig == -1) {
110 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +0200111 str_dig = 0;
112 }
Radek Krejcibf47a822016-11-04 10:06:08 +0100113 /* remove trailing zeros */
114 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +0100115 str_dig -= trailing_zeros;
116 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +0100117 ret = ret / dec_pow(trailing_zeros);
118 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200119
120 /* it's parsed, now adjust the number based on fraction-digits, if needed */
121 if (str_dig < dig) {
122 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200123 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200124 }
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200125 prev_ret = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200126 ret *= dec_pow(dig - str_dig);
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200127 if ((minus && (ret > prev_ret)) || (!minus && (ret < prev_ret))) {
128 return 1;
129 }
130
Michal Vasko4d1f0482016-09-19 14:35:06 +0200131 }
132 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200133 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200134 }
135
Michal Vasko4d1f0482016-09-19 14:35:06 +0200136 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200137 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200138
Michal Vaskod24dd012016-09-30 12:20:22 +0200139 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200140}
141
142/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200143 * @brief Parse an identifier.
144 *
145 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
146 * identifier = (ALPHA / "_")
147 * *(ALPHA / DIGIT / "_" / "-" / ".")
148 *
Michal Vaskobb211122015-08-19 14:03:11 +0200149 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200150 *
151 * @return Number of characters successfully parsed.
152 */
Radek Krejcidce5f972017-09-12 15:47:49 +0200153unsigned int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200154parse_identifier(const char *id)
155{
Radek Krejcidce5f972017-09-12 15:47:49 +0200156 unsigned int parsed = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200157
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100158 assert(id);
159
Radek Krejci6dc53a22015-08-17 13:27:59 +0200160 if (!isalpha(id[0]) && (id[0] != '_')) {
161 return -parsed;
162 }
163
164 ++parsed;
165 ++id;
166
167 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
168 ++parsed;
169 ++id;
170 }
171
172 return parsed;
173}
174
175/**
176 * @brief Parse a node-identifier.
177 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200178 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200179 *
Michal Vaskobb211122015-08-19 14:03:11 +0200180 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200181 * @param[out] mod_name Points to the module name, NULL if there is not any.
182 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200183 * @param[out] name Points to the node name.
184 * @param[out] nam_len Length of the node name.
Michal Vasko50576712017-07-28 12:28:33 +0200185 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
PavolVicanb28bbff2018-02-21 00:44:02 +0100186 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200187 *
188 * @return Number of characters successfully parsed,
189 * positive on success, negative on failure.
190 */
191static int
Michal Vasko50576712017-07-28 12:28:33 +0200192parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
193 int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200194{
PavolVican195cf392018-02-23 13:24:45 +0100195 int parsed = 0, ret, all_desc_local = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200196
197 assert(id);
Michal Vasko50576712017-07-28 12:28:33 +0200198 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
199 assert((name && nam_len) || (!name && !nam_len));
Michal Vasko50576712017-07-28 12:28:33 +0200200
Michal Vasko723e50c2015-10-20 15:20:29 +0200201 if (mod_name) {
202 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200203 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200204 }
205 if (name) {
206 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200207 *nam_len = 0;
208 }
209
Michal Vasko50576712017-07-28 12:28:33 +0200210 if (extended) {
211 /* try to parse only the extended expressions */
212 if (id[parsed] == '/') {
PavolVican195cf392018-02-23 13:24:45 +0100213 if (all_desc) {
214 *all_desc = 1;
215 }
216 all_desc_local = 1;
Michal Vasko50576712017-07-28 12:28:33 +0200217 } else {
PavolVican195cf392018-02-23 13:24:45 +0100218 if (all_desc) {
219 *all_desc = 0;
220 }
Michal Vasko50576712017-07-28 12:28:33 +0200221 }
222
223 /* is there a prefix? */
PavolVican195cf392018-02-23 13:24:45 +0100224 ret = parse_identifier(id + all_desc_local);
Michal Vasko50576712017-07-28 12:28:33 +0200225 if (ret > 0) {
PavolVican195cf392018-02-23 13:24:45 +0100226 if (id[all_desc_local + ret] != ':') {
Michal Vasko50576712017-07-28 12:28:33 +0200227 /* this is not a prefix, so not an extended id */
228 goto standard_id;
229 }
230
231 if (mod_name) {
PavolVican195cf392018-02-23 13:24:45 +0100232 *mod_name = id + all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200233 *mod_name_len = ret;
234 }
235
236 /* "/" and ":" */
PavolVican195cf392018-02-23 13:24:45 +0100237 ret += all_desc_local + 1;
Michal Vasko50576712017-07-28 12:28:33 +0200238 } else {
PavolVican195cf392018-02-23 13:24:45 +0100239 ret = all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200240 }
241
242 /* parse either "*" or "." */
PavolVicanb28bbff2018-02-21 00:44:02 +0100243 if (*(id + ret) == '*') {
Michal Vasko50576712017-07-28 12:28:33 +0200244 if (name) {
245 *name = id + ret;
246 *nam_len = 1;
247 }
248 ++ret;
249
250 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100251 } else if (*(id + ret) == '.') {
PavolVican195cf392018-02-23 13:24:45 +0100252 if (!all_desc_local) {
Michal Vasko50576712017-07-28 12:28:33 +0200253 /* /. is redundant expression, we do not accept it */
254 return -ret;
255 }
256
257 if (name) {
258 *name = id + ret;
259 *nam_len = 1;
260 }
261 ++ret;
262
263 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100264 } else if (*(id + ret) == '#') {
PavolVican195cf392018-02-23 13:24:45 +0100265 if (all_desc_local || !ret) {
PavolVicanb28bbff2018-02-21 00:44:02 +0100266 /* no prefix */
267 return 0;
268 }
269 parsed = ret + 1;
270 if ((ret = parse_identifier(id + parsed)) < 1) {
271 return -parsed + ret;
272 }
273 *name = id + parsed - 1;
274 *nam_len = ret + 1;
275 return parsed + ret;
Michal Vasko50576712017-07-28 12:28:33 +0200276 }
277 /* else a standard id, parse it all again */
278 }
279
280standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200281 if ((ret = parse_identifier(id)) < 1) {
282 return ret;
283 }
284
Michal Vasko723e50c2015-10-20 15:20:29 +0200285 if (mod_name) {
286 *mod_name = id;
Michal Vasko723e50c2015-10-20 15:20:29 +0200287 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200288 }
289
290 parsed += ret;
291 id += ret;
292
293 /* there is prefix */
294 if (id[0] == ':') {
295 ++parsed;
296 ++id;
297
298 /* there isn't */
299 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200300 if (name && mod_name) {
301 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200302 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200303 if (mod_name) {
304 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200305 }
306
Michal Vasko723e50c2015-10-20 15:20:29 +0200307 if (nam_len && mod_name_len) {
308 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200309 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200310 if (mod_name_len) {
311 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200312 }
313
314 return parsed;
315 }
316
317 /* identifier (node name) */
318 if ((ret = parse_identifier(id)) < 1) {
319 return -parsed+ret;
320 }
321
322 if (name) {
323 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200324 *nam_len = ret;
325 }
326
327 return parsed+ret;
328}
329
330/**
331 * @brief Parse a path-predicate (leafref).
332 *
333 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
334 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
335 *
Michal Vaskobb211122015-08-19 14:03:11 +0200336 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200337 * @param[out] prefix Points to the prefix, NULL if there is not any.
338 * @param[out] pref_len Length of the prefix, 0 if there is not any.
339 * @param[out] name Points to the node name.
340 * @param[out] nam_len Length of the node name.
341 * @param[out] path_key_expr Points to the path-key-expr.
342 * @param[out] pke_len Length of the path-key-expr.
343 * @param[out] has_predicate Flag to mark whether there is another predicate following.
344 *
345 * @return Number of characters successfully parsed,
346 * positive on success, negative on failure.
347 */
348static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200349parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
350 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200351{
352 const char *ptr;
353 int parsed = 0, ret;
354
355 assert(id);
356 if (prefix) {
357 *prefix = NULL;
358 }
359 if (pref_len) {
360 *pref_len = 0;
361 }
362 if (name) {
363 *name = NULL;
364 }
365 if (nam_len) {
366 *nam_len = 0;
367 }
368 if (path_key_expr) {
369 *path_key_expr = NULL;
370 }
371 if (pke_len) {
372 *pke_len = 0;
373 }
374 if (has_predicate) {
375 *has_predicate = 0;
376 }
377
378 if (id[0] != '[') {
379 return -parsed;
380 }
381
382 ++parsed;
383 ++id;
384
385 while (isspace(id[0])) {
386 ++parsed;
387 ++id;
388 }
389
Michal Vasko50576712017-07-28 12:28:33 +0200390 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200391 return -parsed+ret;
392 }
393
394 parsed += ret;
395 id += ret;
396
397 while (isspace(id[0])) {
398 ++parsed;
399 ++id;
400 }
401
402 if (id[0] != '=') {
403 return -parsed;
404 }
405
406 ++parsed;
407 ++id;
408
409 while (isspace(id[0])) {
410 ++parsed;
411 ++id;
412 }
413
414 if ((ptr = strchr(id, ']')) == NULL) {
415 return -parsed;
416 }
417
418 --ptr;
419 while (isspace(ptr[0])) {
420 --ptr;
421 }
422 ++ptr;
423
424 ret = ptr-id;
425 if (path_key_expr) {
426 *path_key_expr = id;
427 }
428 if (pke_len) {
429 *pke_len = ret;
430 }
431
432 parsed += ret;
433 id += ret;
434
435 while (isspace(id[0])) {
436 ++parsed;
437 ++id;
438 }
439
440 assert(id[0] == ']');
441
442 if (id[1] == '[') {
443 *has_predicate = 1;
444 }
445
446 return parsed+1;
447}
448
449/**
450 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
451 * the ".." and the first node-identifier, other calls parse a single
452 * node-identifier each.
453 *
454 * path-key-expr = current-function-invocation *WSP "/" *WSP
455 * rel-path-keyexpr
456 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
457 * *(node-identifier *WSP "/" *WSP)
458 * node-identifier
459 *
Michal Vaskobb211122015-08-19 14:03:11 +0200460 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200461 * @param[out] prefix Points to the prefix, NULL if there is not any.
462 * @param[out] pref_len Length of the prefix, 0 if there is not any.
463 * @param[out] name Points to the node name.
464 * @param[out] nam_len Length of the node name.
465 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
466 * must not be changed between consecutive calls.
467 * @return Number of characters successfully parsed,
468 * positive on success, negative on failure.
469 */
470static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200471parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
472 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200473{
474 int parsed = 0, ret, par_times = 0;
475
476 assert(id);
477 assert(parent_times);
478 if (prefix) {
479 *prefix = NULL;
480 }
481 if (pref_len) {
482 *pref_len = 0;
483 }
484 if (name) {
485 *name = NULL;
486 }
487 if (nam_len) {
488 *nam_len = 0;
489 }
490
491 if (!*parent_times) {
492 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
493 if (strncmp(id, "current()", 9)) {
494 return -parsed;
495 }
496
497 parsed += 9;
498 id += 9;
499
500 while (isspace(id[0])) {
501 ++parsed;
502 ++id;
503 }
504
505 if (id[0] != '/') {
506 return -parsed;
507 }
508
509 ++parsed;
510 ++id;
511
512 while (isspace(id[0])) {
513 ++parsed;
514 ++id;
515 }
516
517 /* rel-path-keyexpr */
518 if (strncmp(id, "..", 2)) {
519 return -parsed;
520 }
521 ++par_times;
522
523 parsed += 2;
524 id += 2;
525
526 while (isspace(id[0])) {
527 ++parsed;
528 ++id;
529 }
530 }
531
532 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
533 *
534 * first parent reference with whitespaces already parsed
535 */
536 if (id[0] != '/') {
537 return -parsed;
538 }
539
540 ++parsed;
541 ++id;
542
543 while (isspace(id[0])) {
544 ++parsed;
545 ++id;
546 }
547
548 while (!strncmp(id, "..", 2) && !*parent_times) {
549 ++par_times;
550
551 parsed += 2;
552 id += 2;
553
554 while (isspace(id[0])) {
555 ++parsed;
556 ++id;
557 }
558
559 if (id[0] != '/') {
560 return -parsed;
561 }
562
563 ++parsed;
564 ++id;
565
566 while (isspace(id[0])) {
567 ++parsed;
568 ++id;
569 }
570 }
571
572 if (!*parent_times) {
573 *parent_times = par_times;
574 }
575
576 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200577 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
578 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200579 }
580
581 parsed += ret;
582 id += ret;
583
584 return parsed;
585}
586
587/**
588 * @brief Parse path-arg (leafref).
589 *
590 * path-arg = absolute-path / relative-path
591 * absolute-path = 1*("/" (node-identifier *path-predicate))
592 * relative-path = 1*(".." "/") descendant-path
593 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200594 * @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 +0200595 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 * @param[out] prefix Points to the prefix, NULL if there is not any.
597 * @param[out] pref_len Length of the prefix, 0 if there is not any.
598 * @param[out] name Points to the node name.
599 * @param[out] nam_len Length of the node name.
600 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
601 * must not be changed between consecutive calls. -1 if the
602 * path is relative.
603 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
604 *
605 * @return Number of characters successfully parsed,
606 * positive on success, negative on failure.
607 */
608static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200609parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200610 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200611{
612 int parsed = 0, ret, par_times = 0;
613
614 assert(id);
615 assert(parent_times);
616 if (prefix) {
617 *prefix = NULL;
618 }
619 if (pref_len) {
620 *pref_len = 0;
621 }
622 if (name) {
623 *name = NULL;
624 }
625 if (nam_len) {
626 *nam_len = 0;
627 }
628 if (has_predicate) {
629 *has_predicate = 0;
630 }
631
632 if (!*parent_times && !strncmp(id, "..", 2)) {
633 ++par_times;
634
635 parsed += 2;
636 id += 2;
637
638 while (!strncmp(id, "/..", 3)) {
639 ++par_times;
640
641 parsed += 3;
642 id += 3;
643 }
644 }
645
646 if (!*parent_times) {
647 if (par_times) {
648 *parent_times = par_times;
649 } else {
650 *parent_times = -1;
651 }
652 }
653
654 if (id[0] != '/') {
655 return -parsed;
656 }
657
658 /* skip '/' */
659 ++parsed;
660 ++id;
661
662 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200663 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
664 return -parsed - ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200665 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200666 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200667 /* actually we always need prefix even it is not specified */
668 *prefix = lys_main_module(mod)->name;
669 *pref_len = strlen(*prefix);
670 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200671
672 parsed += ret;
673 id += ret;
674
675 /* there is no predicate */
676 if ((id[0] == '/') || !id[0]) {
677 return parsed;
678 } else if (id[0] != '[') {
679 return -parsed;
680 }
681
682 if (has_predicate) {
683 *has_predicate = 1;
684 }
685
686 return parsed;
687}
688
689/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200690 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200691 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200692 *
693 * instance-identifier = 1*("/" (node-identifier *predicate))
694 *
Michal Vaskobb211122015-08-19 14:03:11 +0200695 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200696 * @param[out] model Points to the model name.
697 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200698 * @param[out] name Points to the node name.
699 * @param[out] nam_len Length of the node name.
700 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
701 *
702 * @return Number of characters successfully parsed,
703 * positive on success, negative on failure.
704 */
705static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200706parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
707 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200708{
709 int parsed = 0, ret;
710
Michal Vasko1b6ca962017-08-03 14:23:09 +0200711 assert(id && model && mod_len && name && nam_len);
712
Radek Krejci6dc53a22015-08-17 13:27:59 +0200713 if (has_predicate) {
714 *has_predicate = 0;
715 }
716
717 if (id[0] != '/') {
718 return -parsed;
719 }
720
721 ++parsed;
722 ++id;
723
Michal Vaskob2f40be2016-09-08 16:03:48 +0200724 if ((ret = parse_identifier(id)) < 1) {
725 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200726 }
727
Michal Vaskob2f40be2016-09-08 16:03:48 +0200728 *name = id;
729 *nam_len = ret;
730
731 parsed += ret;
732 id += ret;
733
Michal Vasko1b6ca962017-08-03 14:23:09 +0200734 if (id[0] == ':') {
735 /* we have prefix */
736 *model = *name;
737 *mod_len = *nam_len;
738
739 ++parsed;
740 ++id;
741
742 if ((ret = parse_identifier(id)) < 1) {
743 return ret;
744 }
745
746 *name = id;
747 *nam_len = ret;
748
749 parsed += ret;
750 id += ret;
751 }
752
Radek Krejci4967cb62016-09-14 16:40:28 +0200753 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200754 *has_predicate = 1;
755 }
756
757 return parsed;
758}
759
760/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200761 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200762 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200763 *
764 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
765 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
766 * ((DQUOTE string DQUOTE) /
767 * (SQUOTE string SQUOTE))
768 * pos = non-negative-integer-value
769 *
Michal Vaskobb211122015-08-19 14:03:11 +0200770 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200771 * @param[out] model Points to the model name.
772 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200773 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
774 * @param[out] nam_len Length of the node name.
775 * @param[out] value Value the node-identifier must have (string from the grammar),
776 * NULL if there is not any.
777 * @param[out] val_len Length of the value, 0 if there is not any.
778 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
779 *
780 * @return Number of characters successfully parsed,
781 * positive on success, negative on failure.
782 */
783static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200784parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
785 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200786{
787 const char *ptr;
788 int parsed = 0, ret;
789 char quote;
790
791 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200792 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200793 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200794 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200795 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200796 }
797 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200798 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200799 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200800 *nam_len = 0;
801 }
802 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200803 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200804 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200805 *val_len = 0;
806 }
807 if (has_predicate) {
808 *has_predicate = 0;
809 }
810
811 if (id[0] != '[') {
812 return -parsed;
813 }
814
815 ++parsed;
816 ++id;
817
818 while (isspace(id[0])) {
819 ++parsed;
820 ++id;
821 }
822
823 /* pos */
824 if (isdigit(id[0])) {
825 if (name) {
826 *name = id;
827 }
828
829 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200830 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200831 }
832
833 while (isdigit(id[0])) {
834 ++parsed;
835 ++id;
836 }
837
838 if (nam_len) {
839 *nam_len = id-(*name);
840 }
841
Michal Vaskof2f28a12016-09-09 12:43:06 +0200842 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200843 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200844 if (id[0] == '.') {
845 if (name) {
846 *name = id;
847 }
848 if (nam_len) {
849 *nam_len = 1;
850 }
851
852 ++parsed;
853 ++id;
854
855 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200856 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200857 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200858 }
859
860 parsed += ret;
861 id += ret;
862 }
863
864 while (isspace(id[0])) {
865 ++parsed;
866 ++id;
867 }
868
869 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200870 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200871 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200872
Radek Krejci6dc53a22015-08-17 13:27:59 +0200873 ++parsed;
874 ++id;
875
Michal Vaskof2f28a12016-09-09 12:43:06 +0200876 while (isspace(id[0])) {
877 ++parsed;
878 ++id;
879 }
880
881 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
882 if ((id[0] == '\"') || (id[0] == '\'')) {
883 quote = id[0];
884
885 ++parsed;
886 ++id;
887
888 if ((ptr = strchr(id, quote)) == NULL) {
889 return -parsed;
890 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200891 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200892
893 if (value) {
894 *value = id;
895 }
896 if (val_len) {
897 *val_len = ret;
898 }
899
Michal Vasko1b6ca962017-08-03 14:23:09 +0200900 parsed += ret + 1;
901 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200902 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200903 return -parsed;
904 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200905 }
906
907 while (isspace(id[0])) {
908 ++parsed;
909 ++id;
910 }
911
912 if (id[0] != ']') {
913 return -parsed;
914 }
915
916 ++parsed;
917 ++id;
918
919 if ((id[0] == '[') && has_predicate) {
920 *has_predicate = 1;
921 }
922
923 return parsed;
924}
925
926/**
927 * @brief Parse schema-nodeid.
928 *
929 * schema-nodeid = absolute-schema-nodeid /
930 * descendant-schema-nodeid
931 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200932 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200933 * node-identifier
934 * absolute-schema-nodeid
935 *
Michal Vaskobb211122015-08-19 14:03:11 +0200936 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200937 * @param[out] mod_name Points to the module name, NULL if there is not any.
938 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200939 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200940 * @param[out] nam_len Length of the node name.
941 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
942 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100943 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
944 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200945 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200946 *
947 * @return Number of characters successfully parsed,
948 * positive on success, negative on failure.
949 */
Michal Vasko22448d32016-03-16 13:17:29 +0100950int
Michal Vasko723e50c2015-10-20 15:20:29 +0200951parse_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 +0200952 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200953{
954 int parsed = 0, ret;
955
956 assert(id);
957 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200958
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100959 if (has_predicate) {
960 *has_predicate = 0;
961 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200962
963 if (id[0] != '/') {
964 if (*is_relative != -1) {
965 return -parsed;
966 } else {
967 *is_relative = 1;
968 }
Michal Vasko48935352016-03-29 11:52:36 +0200969 if (!strncmp(id, "./", 2)) {
970 parsed += 2;
971 id += 2;
972 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200973 } else {
974 if (*is_relative == -1) {
975 *is_relative = 0;
976 }
977 ++parsed;
978 ++id;
979 }
980
Michal Vasko50576712017-07-28 12:28:33 +0200981 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
982 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200983 }
984
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100985 parsed += ret;
986 id += ret;
987
988 if ((id[0] == '[') && has_predicate) {
989 *has_predicate = 1;
990 }
991
992 return parsed;
993}
994
995/**
996 * @brief Parse schema predicate (special format internally used).
997 *
998 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +0200999 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001000 * key-with-value = identifier *WSP "=" *WSP
1001 * ((DQUOTE string DQUOTE) /
1002 * (SQUOTE string SQUOTE))
1003 *
1004 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001005 * @param[out] mod_name Points to the list key module name.
1006 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001007 * @param[out] name Points to the list key name.
1008 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +01001009 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001010 * @param[out] val_len Length of \p value.
1011 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
1012 */
Michal Vasko22448d32016-03-16 13:17:29 +01001013int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001014parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1015 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001016{
1017 const char *ptr;
1018 int parsed = 0, ret;
1019 char quote;
1020
1021 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001022 if (mod_name) {
1023 *mod_name = NULL;
1024 }
1025 if (mod_name_len) {
1026 *mod_name_len = 0;
1027 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001028 if (name) {
1029 *name = NULL;
1030 }
1031 if (nam_len) {
1032 *nam_len = 0;
1033 }
1034 if (value) {
1035 *value = NULL;
1036 }
1037 if (val_len) {
1038 *val_len = 0;
1039 }
1040 if (has_predicate) {
1041 *has_predicate = 0;
1042 }
1043
1044 if (id[0] != '[') {
1045 return -parsed;
1046 }
1047
1048 ++parsed;
1049 ++id;
1050
1051 while (isspace(id[0])) {
1052 ++parsed;
1053 ++id;
1054 }
1055
Michal Vasko22448d32016-03-16 13:17:29 +01001056 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001057 if (id[0] == '.') {
1058 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001059
1060 if (name) {
1061 *name = id;
1062 }
1063 if (nam_len) {
1064 *nam_len = ret;
1065 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001066 } else if (isdigit(id[0])) {
1067 if (id[0] == '0') {
1068 return -parsed;
1069 }
1070 ret = 1;
1071 while (isdigit(id[ret])) {
1072 ++ret;
1073 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001074
1075 if (name) {
1076 *name = id;
1077 }
1078 if (nam_len) {
1079 *nam_len = ret;
1080 }
Michal Vasko50576712017-07-28 12:28:33 +02001081 } 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 +01001082 return -parsed + ret;
1083 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001084
1085 parsed += ret;
1086 id += ret;
1087
1088 while (isspace(id[0])) {
1089 ++parsed;
1090 ++id;
1091 }
1092
1093 /* there is value as well */
1094 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001095 if (name && isdigit(**name)) {
1096 return -parsed;
1097 }
1098
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001099 ++parsed;
1100 ++id;
1101
1102 while (isspace(id[0])) {
1103 ++parsed;
1104 ++id;
1105 }
1106
1107 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1108 if ((id[0] == '\"') || (id[0] == '\'')) {
1109 quote = id[0];
1110
1111 ++parsed;
1112 ++id;
1113
1114 if ((ptr = strchr(id, quote)) == NULL) {
1115 return -parsed;
1116 }
1117 ret = ptr - id;
1118
1119 if (value) {
1120 *value = id;
1121 }
1122 if (val_len) {
1123 *val_len = ret;
1124 }
1125
1126 parsed += ret + 1;
1127 id += ret + 1;
1128 } else {
1129 return -parsed;
1130 }
1131
1132 while (isspace(id[0])) {
1133 ++parsed;
1134 ++id;
1135 }
1136 }
1137
1138 if (id[0] != ']') {
1139 return -parsed;
1140 }
1141
1142 ++parsed;
1143 ++id;
1144
1145 if ((id[0] == '[') && has_predicate) {
1146 *has_predicate = 1;
1147 }
1148
1149 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001150}
1151
Michal Vasko2d44ee02018-05-18 09:38:51 +02001152#ifdef LY_ENABLED_CACHE
1153
1154static int
1155resolve_hash_table_find_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
1156{
1157 struct lyd_node *val2, *elem2;
1158 struct parsed_pred pp;
1159 const char *str;
1160 int i;
1161
1162 assert(!mod);
Michal Vasko87e29a82018-05-21 13:50:43 +02001163 (void)mod;
Michal Vasko2d44ee02018-05-18 09:38:51 +02001164
1165 pp = *((struct parsed_pred *)val1_p);
1166 val2 = *((struct lyd_node **)val2_p);
1167
1168 if (val2->schema != pp.schema) {
1169 return 0;
1170 }
1171
1172 switch (val2->schema->nodetype) {
1173 case LYS_CONTAINER:
1174 case LYS_LEAF:
1175 case LYS_ANYXML:
1176 case LYS_ANYDATA:
1177 return 1;
1178 case LYS_LEAFLIST:
1179 str = ((struct lyd_node_leaf_list *)val2)->value_str;
1180 if (!strncmp(str, pp.pred[0].value, pp.pred[0].val_len) && !str[pp.pred[0].val_len]) {
1181 return 1;
1182 }
1183 return 0;
1184 case LYS_LIST:
1185 assert(((struct lys_node_list *)val2->schema)->keys_size);
1186 assert(((struct lys_node_list *)val2->schema)->keys_size == pp.len);
1187
1188 /* lists with keys, their equivalence is based on their keys */
1189 elem2 = val2->child;
1190 /* the exact data order is guaranteed */
1191 for (i = 0; elem2 && (i < pp.len); ++i) {
1192 /* module check */
1193 if (pp.pred[i].mod_name) {
1194 if (strncmp(lyd_node_module(elem2)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
1195 || lyd_node_module(elem2)->name[pp.pred[i].mod_name_len]) {
1196 break;
1197 }
1198 } else {
1199 if (lyd_node_module(elem2) != lys_node_module(pp.schema)) {
1200 break;
1201 }
1202 }
1203
1204 /* name check */
1205 if (strncmp(elem2->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || elem2->schema->name[pp.pred[i].nam_len]) {
1206 break;
1207 }
1208
1209 /* value check */
1210 str = ((struct lyd_node_leaf_list *)elem2)->value_str;
1211 if (strncmp(str, pp.pred[i].value, pp.pred[i].val_len) || str[pp.pred[i].val_len]) {
1212 break;
1213 }
1214
1215 /* next key */
1216 elem2 = elem2->next;
1217 }
1218 if (i == pp.len) {
1219 return 1;
1220 }
1221 return 0;
1222 default:
1223 break;
1224 }
1225
1226 LOGINT(val2->schema->module->ctx);
1227 return 0;
1228}
1229
1230static struct lyd_node *
1231resolve_json_data_node_hash(struct lyd_node *parent, struct parsed_pred pp)
1232{
1233 values_equal_cb prev_cb;
1234 struct lyd_node **ret = NULL;
1235 uint32_t hash;
1236 int i;
1237
1238 assert(parent && parent->hash);
1239
1240 /* set our value equivalence callback that does not require data nodes */
1241 prev_cb = lyht_set_cb(parent->ht, resolve_hash_table_find_equal);
1242
1243 /* get the hash of the searched node */
1244 hash = dict_hash_multi(0, lys_node_module(pp.schema)->name, strlen(lys_node_module(pp.schema)->name));
1245 hash = dict_hash_multi(hash, pp.schema->name, strlen(pp.schema->name));
1246 if (pp.schema->nodetype == LYS_LEAFLIST) {
1247 assert((pp.len == 1) && (pp.pred[0].name[0] == '.') && (pp.pred[0].nam_len == 1));
1248 /* leaf-list value in predicate */
1249 hash = dict_hash_multi(hash, pp.pred[0].value, pp.pred[0].val_len);
1250 } else if (pp.schema->nodetype == LYS_LIST) {
1251 /* list keys in predicates */
1252 for (i = 0; i < pp.len; ++i) {
1253 hash = dict_hash_multi(hash, pp.pred[i].value, pp.pred[i].val_len);
1254 }
1255 }
1256 hash = dict_hash_multi(hash, NULL, 0);
1257
1258 /* try to find the node */
1259 lyht_find(parent->ht, &pp, hash, (void **)&ret);
1260
1261 /* restore the original callback */
1262 lyht_set_cb(parent->ht, prev_cb);
1263
1264 return (ret ? *ret : NULL);
1265}
1266
1267#endif
1268
Radek Krejci6dc53a22015-08-17 13:27:59 +02001269/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001270 * @brief Resolve (find) a feature definition. Logs directly.
1271 *
1272 * @param[in] feat_name Feature name to resolve.
1273 * @param[in] len Length of \p feat_name.
1274 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001275 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1276 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001277 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001278 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001279 */
1280static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001281resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001282{
1283 char *str;
1284 const char *mod_name, *name;
1285 int mod_name_len, nam_len, i, j;
1286 const struct lys_module *module;
1287
Radek Krejci9ff0a922016-07-14 13:08:05 +02001288 assert(feature);
1289
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001290 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001291 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 +01001292 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001293 return -1;
1294 }
1295
Michal Vasko921eb6b2017-10-13 10:01:39 +02001296 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001297 if (!module) {
1298 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01001299 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001300 return -1;
1301 }
1302
Radek Krejci9ff0a922016-07-14 13:08:05 +02001303 if (module != node->module && module == lys_node_module(node)) {
1304 /* first, try to search directly in submodule where the feature was mentioned */
1305 for (j = 0; j < node->module->features_size; j++) {
1306 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1307 /* check status */
1308 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001309 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001310 return -1;
1311 }
1312 *feature = &node->module->features[j];
1313 return 0;
1314 }
1315 }
1316 }
1317
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001318 /* search in the identified module ... */
1319 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001320 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001321 /* check status */
1322 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001323 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001324 return -1;
1325 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326 *feature = &module->features[j];
1327 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001328 }
1329 }
1330 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001331 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001332 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001333 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1334 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001335 /* check status */
1336 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1337 module->inc[i].submodule->features[j].flags,
1338 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001339 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001340 return -1;
1341 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001342 *feature = &module->inc[i].submodule->features[j];
1343 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001344 }
1345 }
1346 }
1347
1348 /* not found */
1349 str = strndup(feat_name, len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001350 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001351 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001352 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001353}
1354
Radek Krejci9ff0a922016-07-14 13:08:05 +02001355/*
1356 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001357 * - 1 if enabled
1358 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001359 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001360static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001361resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001362{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001363 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001364
Radek Krejci9ff0a922016-07-14 13:08:05 +02001365 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001366 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001367 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001368 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001369 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001370
Radek Krejci69b8d922016-07-27 13:13:41 +02001371 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001372}
1373
1374static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001375resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001376{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001377 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001378 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001379
Radek Krejci9ff0a922016-07-14 13:08:05 +02001380 op = iff_getop(expr->expr, *index_e);
1381 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001382
Radek Krejci9ff0a922016-07-14 13:08:05 +02001383 switch (op) {
1384 case LYS_IFF_F:
1385 /* resolve feature */
1386 return resolve_feature_value(expr->features[(*index_f)++]);
1387 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001388 /* invert result */
1389 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 case LYS_IFF_AND:
1391 case LYS_IFF_OR:
1392 a = resolve_iffeature_recursive(expr, index_e, index_f);
1393 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001394 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001395 return a && b;
1396 } else { /* LYS_IFF_OR */
1397 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001398 }
1399 }
1400
Radek Krejciaf566332017-02-07 15:56:59 +01001401 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001402}
1403
1404int
1405resolve_iffeature(struct lys_iffeature *expr)
1406{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001407 int index_e = 0, index_f = 0;
1408
1409 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001410 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001411 }
Radek Krejciaf566332017-02-07 15:56:59 +01001412 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001413}
1414
1415struct iff_stack {
1416 int size;
1417 int index; /* first empty item */
1418 uint8_t *stack;
1419};
1420
1421static int
1422iff_stack_push(struct iff_stack *stack, uint8_t value)
1423{
1424 if (stack->index == stack->size) {
1425 stack->size += 4;
1426 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001427 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001428 }
1429
1430 stack->stack[stack->index++] = value;
1431 return EXIT_SUCCESS;
1432}
1433
1434static uint8_t
1435iff_stack_pop(struct iff_stack *stack)
1436{
1437 stack->index--;
1438 return stack->stack[stack->index];
1439}
1440
1441static void
1442iff_stack_clean(struct iff_stack *stack)
1443{
1444 stack->size = 0;
1445 free(stack->stack);
1446}
1447
1448static void
1449iff_setop(uint8_t *list, uint8_t op, int pos)
1450{
1451 uint8_t *item;
1452 uint8_t mask = 3;
1453
1454 assert(pos >= 0);
1455 assert(op <= 3); /* max 2 bits */
1456
1457 item = &list[pos / 4];
1458 mask = mask << 2 * (pos % 4);
1459 *item = (*item) & ~mask;
1460 *item = (*item) | (op << 2 * (pos % 4));
1461}
1462
1463uint8_t
1464iff_getop(uint8_t *list, int pos)
1465{
1466 uint8_t *item;
1467 uint8_t mask = 3, result;
1468
1469 assert(pos >= 0);
1470
1471 item = &list[pos / 4];
1472 result = (*item) & (mask << 2 * (pos % 4));
1473 return result >> 2 * (pos % 4);
1474}
1475
1476#define LYS_IFF_LP 0x04 /* ( */
1477#define LYS_IFF_RP 0x08 /* ) */
1478
Radek Krejcicbb473e2016-09-16 14:48:32 +02001479/* internal structure for passing data for UNRES_IFFEAT */
1480struct unres_iffeat_data {
1481 struct lys_node *node;
1482 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001483 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001484};
1485
Radek Krejci9ff0a922016-07-14 13:08:05 +02001486void
1487resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1488{
1489 unsigned int e = 0, f = 0, r = 0;
1490 uint8_t op;
1491
1492 assert(iffeat);
1493
1494 if (!iffeat->expr) {
1495 goto result;
1496 }
1497
1498 do {
1499 op = iff_getop(iffeat->expr, e++);
1500 switch (op) {
1501 case LYS_IFF_NOT:
1502 if (!r) {
1503 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001504 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001505 break;
1506 case LYS_IFF_AND:
1507 case LYS_IFF_OR:
1508 if (!r) {
1509 r += 2;
1510 } else {
1511 r += 1;
1512 }
1513 break;
1514 case LYS_IFF_F:
1515 f++;
1516 if (r) {
1517 r--;
1518 }
1519 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001520 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001521 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001522
Radek Krejci9ff0a922016-07-14 13:08:05 +02001523result:
1524 if (expr_size) {
1525 *expr_size = e;
1526 }
1527 if (feat_size) {
1528 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001529 }
1530}
1531
1532int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001533resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001534 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001535{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001536 const char *c = value;
1537 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001538 int i, j, last_not, checkversion = 0;
1539 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001540 uint8_t op;
1541 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001542 struct unres_iffeat_data *iff_data;
Michal Vasko53b7da02018-02-13 15:28:42 +01001543 struct ly_ctx *ctx = node->module->ctx;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001544
Radek Krejci9ff0a922016-07-14 13:08:05 +02001545 assert(c);
1546
1547 if (isspace(c[0])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001548 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001549 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001550 }
1551
Radek Krejci9ff0a922016-07-14 13:08:05 +02001552 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1553 for (i = j = last_not = 0; c[i]; i++) {
1554 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001555 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001556 j++;
1557 continue;
1558 } else if (c[i] == ')') {
1559 j--;
1560 continue;
1561 } else if (isspace(c[i])) {
1562 continue;
1563 }
1564
1565 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1566 if (c[i + r] == '\0') {
Michal Vasko53b7da02018-02-13 15:28:42 +01001567 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001568 return EXIT_FAILURE;
1569 } else if (!isspace(c[i + r])) {
1570 /* feature name starting with the not/and/or */
1571 last_not = 0;
1572 f_size++;
1573 } else if (c[i] == 'n') { /* not operation */
1574 if (last_not) {
1575 /* double not */
1576 expr_size = expr_size - 2;
1577 last_not = 0;
1578 } else {
1579 last_not = 1;
1580 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001581 } else { /* and, or */
1582 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001583 /* not a not operation */
1584 last_not = 0;
1585 }
1586 i += r;
1587 } else {
1588 f_size++;
1589 last_not = 0;
1590 }
1591 expr_size++;
1592
1593 while (!isspace(c[i])) {
1594 if (!c[i] || c[i] == ')') {
1595 i--;
1596 break;
1597 }
1598 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001599 }
1600 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001601 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001602 /* not matching count of ( and ) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001603 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001604 return EXIT_FAILURE;
1605 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001606
Radek Krejci69b8d922016-07-27 13:13:41 +02001607 if (checkversion || expr_size > 1) {
1608 /* check that we have 1.1 module */
Radek Krejci13fde922018-05-16 10:45:58 +02001609 if (node->module->version != LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001610 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1611 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 +02001612 return EXIT_FAILURE;
1613 }
1614 }
1615
Radek Krejci9ff0a922016-07-14 13:08:05 +02001616 /* allocate the memory */
1617 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001618 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001619 stack.stack = malloc(expr_size * sizeof *stack.stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001620 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001621 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001622 f_size--; expr_size--; /* used as indexes from now */
1623
1624 for (i--; i >= 0; i--) {
1625 if (c[i] == ')') {
1626 /* push it on stack */
1627 iff_stack_push(&stack, LYS_IFF_RP);
1628 continue;
1629 } else if (c[i] == '(') {
1630 /* pop from the stack into result all operators until ) */
1631 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1632 iff_setop(iffeat_expr->expr, op, expr_size--);
1633 }
1634 continue;
1635 } else if (isspace(c[i])) {
1636 continue;
1637 }
1638
1639 /* end operator or operand -> find beginning and get what is it */
1640 j = i + 1;
1641 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1642 i--;
1643 }
1644 i++; /* get back by one step */
1645
1646 if (!strncmp(&c[i], "not ", 4)) {
1647 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1648 /* double not */
1649 iff_stack_pop(&stack);
1650 } else {
1651 /* not has the highest priority, so do not pop from the stack
1652 * as in case of AND and OR */
1653 iff_stack_push(&stack, LYS_IFF_NOT);
1654 }
1655 } else if (!strncmp(&c[i], "and ", 4)) {
1656 /* as for OR - pop from the stack all operators with the same or higher
1657 * priority and store them to the result, then push the AND to the stack */
1658 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1659 op = iff_stack_pop(&stack);
1660 iff_setop(iffeat_expr->expr, op, expr_size--);
1661 }
1662 iff_stack_push(&stack, LYS_IFF_AND);
1663 } else if (!strncmp(&c[i], "or ", 3)) {
1664 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1665 op = iff_stack_pop(&stack);
1666 iff_setop(iffeat_expr->expr, op, expr_size--);
1667 }
1668 iff_stack_push(&stack, LYS_IFF_OR);
1669 } else {
1670 /* feature name, length is j - i */
1671
1672 /* add it to the result */
1673 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1674
1675 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001676 * forward referenced, we have to keep the feature name in auxiliary
1677 * structure passed into unres */
1678 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01001679 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001680 iff_data->node = node;
1681 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001682 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001683 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1684 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001685 f_size--;
1686
1687 if (r == -1) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01001688 lydict_remove(node->module->ctx, iff_data->fname);
Pavol Vican4d084512016-09-29 16:38:12 +02001689 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001690 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001691 }
1692 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001693 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001694 while (stack.index) {
1695 op = iff_stack_pop(&stack);
1696 iff_setop(iffeat_expr->expr, op, expr_size--);
1697 }
1698
1699 if (++expr_size || ++f_size) {
1700 /* not all expected operators and operands found */
Michal Vasko53b7da02018-02-13 15:28:42 +01001701 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001702 rc = EXIT_FAILURE;
1703 } else {
1704 rc = EXIT_SUCCESS;
1705 }
1706
1707error:
1708 /* cleanup */
1709 iff_stack_clean(&stack);
1710
1711 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001712}
1713
1714/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001715 * @brief Resolve (find) a data node based on a schema-nodeid.
1716 *
1717 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1718 * module).
1719 *
1720 */
1721struct lyd_node *
1722resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1723{
1724 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001725 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726 const struct lys_node *schema = NULL;
1727
1728 assert(nodeid && start);
1729
1730 if (nodeid[0] == '/') {
1731 return NULL;
1732 }
1733
1734 str = p = strdup(nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01001735 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001736
Michal Vasko3edeaf72016-02-11 13:17:43 +01001737 while (p) {
1738 token = p;
1739 p = strchr(p, '/');
1740 if (p) {
1741 *p = '\0';
1742 p++;
1743 }
1744
Radek Krejci5da4eb62016-04-08 14:45:51 +02001745 if (p) {
1746 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001747 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001748 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001749 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001750 result = NULL;
1751 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001752 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001753
Radek Krejci5da4eb62016-04-08 14:45:51 +02001754 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1755 continue;
1756 }
1757 } else {
1758 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001759 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001760 || !schema) {
1761 result = NULL;
1762 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763 }
1764 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001765 LY_TREE_FOR(result ? result->child : start, iter) {
1766 if (iter->schema == schema) {
1767 /* move in data tree according to returned schema */
1768 result = iter;
1769 break;
1770 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001771 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001772 if (!iter) {
1773 /* instance not found */
1774 result = NULL;
1775 break;
1776 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001777 }
1778 free(str);
1779
1780 return result;
1781}
1782
Radek Krejci1a9c3612017-04-24 14:49:43 +02001783int
Michal Vasko50576712017-07-28 12:28:33 +02001784schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1785 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001786{
1787 const struct lys_module *prefix_mod;
1788
Michal Vaskocdb3f062018-02-01 09:55:06 +01001789 /* handle special names */
1790 if (name[0] == '*') {
1791 return 2;
1792 } else if (name[0] == '.') {
1793 return 3;
1794 }
1795
Michal Vasko50576712017-07-28 12:28:33 +02001796 /* name check */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001797 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02001798 return 1;
1799 }
1800
Radek Krejcibdf92362016-04-08 14:43:34 +02001801 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001802 if (mod_name) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001803 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vasko50576712017-07-28 12:28:33 +02001804 if (!prefix_mod) {
1805 return -1;
1806 }
1807 } else {
1808 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001809 }
1810 if (prefix_mod != lys_node_module(sibling)) {
1811 return 1;
1812 }
1813
Michal Vasko50576712017-07-28 12:28:33 +02001814 /* match */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001815 return 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001816}
1817
Michal Vasko50576712017-07-28 12:28:33 +02001818/* keys do not have to be ordered and do not have to be all of them */
1819static int
1820resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1821 const struct lys_module *cur_module, int *nodeid_end)
1822{
1823 int mod_len, nam_len, has_predicate, r, i;
1824 const char *model, *name;
1825 struct lys_node_list *list;
1826
1827 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1828 return 1;
1829 }
1830
1831 list = (struct lys_node_list *)node;
1832 do {
1833 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1834 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001835 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001836 return -1;
1837 }
1838 nodeid += r;
1839
1840 if (node->nodetype == LYS_LEAFLIST) {
1841 /* just check syntax */
1842 if (model || !name || (name[0] != '.') || has_predicate) {
1843 return 1;
1844 }
1845 break;
1846 } else {
1847 /* check the key */
1848 for (i = 0; i < list->keys_size; ++i) {
1849 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1850 continue;
1851 }
1852 if (model) {
1853 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1854 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1855 continue;
1856 }
1857 } else {
1858 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1859 continue;
1860 }
1861 }
1862
1863 /* match */
1864 break;
1865 }
1866
1867 if (i == list->keys_size) {
1868 return 1;
1869 }
1870 }
1871 } while (has_predicate);
1872
1873 if (!nodeid[0]) {
1874 *nodeid_end = 1;
1875 }
1876 return 0;
1877}
1878
Michal Vasko97234262018-02-01 09:53:01 +01001879/* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001880 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001881int
Michal Vasko97234262018-02-01 09:53:01 +01001882resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
Michal Vasko50576712017-07-28 12:28:33 +02001883 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001884{
PavolVicanb28bbff2018-02-21 00:44:02 +01001885 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vasko97234262018-02-01 09:53:01 +01001886 const struct lys_node *sibling, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001887 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001888 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
PavolVicanb28bbff2018-02-21 00:44:02 +01001889 int yang_data_name_len, backup_mod_name_len = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001890 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidaa547a2017-09-22 15:56:27 +02001891 const struct lys_module *start_mod, *aux_mod = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02001892 char *str;
Michal Vasko53b7da02018-02-13 15:28:42 +01001893 struct ly_ctx *ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001894
Michal Vasko97234262018-02-01 09:53:01 +01001895 assert(nodeid && (start_parent || cur_module) && ret);
Michal Vasko50576712017-07-28 12:28:33 +02001896 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001897
Michal Vasko50576712017-07-28 12:28:33 +02001898 if (!cur_module) {
Michal Vasko97234262018-02-01 09:53:01 +01001899 cur_module = lys_node_module(start_parent);
Michal Vasko50576712017-07-28 12:28:33 +02001900 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001901 ctx = cur_module->ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001902 id = nodeid;
1903
PavolVican195cf392018-02-23 13:24:45 +01001904 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
PavolVicanb28bbff2018-02-21 00:44:02 +01001905 if (r < 1) {
1906 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1907 return -1;
1908 }
1909
1910 if (name[0] == '#') {
1911 if (is_relative) {
1912 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1913 return -1;
1914 }
1915 yang_data_name = name + 1;
1916 yang_data_name_len = nam_len - 1;
1917 backup_mod_name = mod_name;
1918 backup_mod_name_len = mod_name_len;
1919 id += r;
1920 } else {
1921 is_relative = -1;
1922 }
1923
Michal Vasko50576712017-07-28 12:28:33 +02001924 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1925 (extended ? &all_desc : NULL), extended);
1926 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001927 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001928 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001929 }
1930 id += r;
1931
PavolVicanb28bbff2018-02-21 00:44:02 +01001932 if (backup_mod_name) {
1933 mod_name = backup_mod_name;
1934 mod_name_len = backup_mod_name_len;
1935 }
1936
Michal Vasko97234262018-02-01 09:53:01 +01001937 if (is_relative && !start_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001938 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
Michal Vasko3edeaf72016-02-11 13:17:43 +01001939 return -1;
1940 }
1941
1942 /* descendant-schema-nodeid */
1943 if (is_relative) {
Michal Vasko97234262018-02-01 09:53:01 +01001944 cur_module = start_mod = lys_node_module(start_parent);
Michal Vasko24476fa2017-03-08 12:33:48 +01001945
Michal Vasko3edeaf72016-02-11 13:17:43 +01001946 /* absolute-schema-nodeid */
1947 } else {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001948 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01001949 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001950 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001951 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001952 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001953 return -1;
1954 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001955 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01001956 if (yang_data_name) {
1957 start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1958 if (!start_parent) {
1959 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1960 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1961 free(str);
1962 return -1;
1963 }
1964 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001965 }
1966
1967 while (1) {
1968 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001969 last_aug = NULL;
1970
1971 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001972 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1973 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001974 /* we are getting into another module (augment) */
Michal Vasko921eb6b2017-10-13 10:01:39 +02001975 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskobb520442017-05-23 10:55:18 +02001976 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001977 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001978 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001979 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001980 return -1;
1981 }
1982 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001983 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001984 * because this module may be not implemented and it augments something in another module and
1985 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001986 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001987 }
1988
1989 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001990 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001991get_next_augment:
1992 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1993 }
1994 }
1995
1996 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vaskocb45f472018-02-12 10:47:42 +01001997 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02001998 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1999
2000 /* resolve predicate */
2001 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
2002 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
2003 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002004 continue;
Michal Vasko50576712017-07-28 12:28:33 +02002005 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002006 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002007 }
Michal Vasko50576712017-07-28 12:28:33 +02002008 } else if (!id[0]) {
2009 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002010 }
Michal Vasko50576712017-07-28 12:28:33 +02002011
2012 if (r == 0) {
2013 /* one matching result */
2014 if (nodeid_end) {
2015 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002016 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002017 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2018 } else {
2019 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2020 return -1;
2021 }
2022 start_parent = sibling;
2023 }
2024 break;
2025 } else if (r == 1) {
2026 continue;
2027 } else if (r == 2) {
2028 /* "*" */
2029 if (!*ret) {
2030 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002031 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002032 }
2033 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2034 if (all_desc) {
2035 LY_TREE_DFS_BEGIN(sibling, next, elem) {
2036 if (elem != sibling) {
2037 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2038 }
2039
2040 LY_TREE_DFS_END(sibling, next, elem);
2041 }
2042 }
2043 } else if (r == 3) {
2044 /* "." */
2045 if (!*ret) {
2046 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002047 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002048 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
2049 }
2050 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2051 if (all_desc) {
2052 LY_TREE_DFS_BEGIN(sibling, next, elem) {
2053 if (elem != sibling) {
2054 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2055 }
2056
2057 LY_TREE_DFS_END(sibling, next, elem);
2058 }
2059 }
2060 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002061 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02002062 return -1;
2063 }
2064 }
2065
2066 /* skip predicate */
2067 if (extended && has_predicate) {
2068 while (id[0] == '[') {
2069 id = strchr(id, ']');
2070 if (!id) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002071 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02002072 return -1;
2073 }
2074 ++id;
2075 }
2076 }
2077
2078 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
2079 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002080 }
2081
2082 /* no match */
2083 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02002084 if (last_aug) {
2085 /* it still could be in another augment */
2086 goto get_next_augment;
2087 }
Michal Vasko50576712017-07-28 12:28:33 +02002088 if (no_node_error) {
2089 str = strndup(nodeid, (name - nodeid) + nam_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01002090 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02002091 free(str);
2092 return -1;
2093 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01002094 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002095 return EXIT_SUCCESS;
2096 }
2097
Michal Vasko50576712017-07-28 12:28:33 +02002098 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
2099 (extended ? &all_desc : NULL), extended);
2100 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002101 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02002102 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002103 }
2104 id += r;
2105 }
2106
2107 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002108 LOGINT(ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002109 return -1;
2110}
2111
Radek Krejcif3c71de2016-04-11 12:45:46 +02002112/* unique, refine,
2113 * >0 - unexpected char on position (ret - 1),
2114 * 0 - ok (but ret can still be NULL),
2115 * -1 - error,
2116 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002117int
2118resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02002119 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002120{
2121 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002122 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002123 int r, nam_len, mod_name_len, is_relative = -1;
2124 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02002125 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002126
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002127 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01002128 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01002129
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002130 if (!start) {
2131 /* leaf not found */
2132 return 0;
2133 }
2134
Michal Vasko3edeaf72016-02-11 13:17:43 +01002135 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02002136 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002137
Michal Vasko50576712017-07-28 12:28:33 +02002138 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 +01002139 return ((id - nodeid) - r) + 1;
2140 }
2141 id += r;
2142
2143 if (!is_relative) {
2144 return -1;
2145 }
2146
Michal Vasko24476fa2017-03-08 12:33:48 +01002147 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02002148 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01002149 start_parent = lys_parent(start_parent);
2150 }
2151
Michal Vasko3edeaf72016-02-11 13:17:43 +01002152 while (1) {
2153 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002154 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vaskocb45f472018-02-12 10:47:42 +01002155 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002156 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2157 if (r == 0) {
2158 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002159 if (!(sibling->nodetype & ret_nodetype)) {
2160 /* wrong node type, too bad */
2161 continue;
2162 }
2163 *ret = sibling;
2164 return EXIT_SUCCESS;
2165 }
Michal Vasko50576712017-07-28 12:28:33 +02002166 start_parent = sibling;
2167 break;
2168 } else if (r == 1) {
2169 continue;
2170 } else {
2171 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002172 }
2173 }
2174
2175 /* no match */
2176 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002177 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002178 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02002179 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2180 *ret = NULL;
2181 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002182 }
2183
Michal Vasko50576712017-07-28 12:28:33 +02002184 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 +01002185 return ((id - nodeid) - r) + 1;
2186 }
2187 id += r;
2188 }
2189
2190 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002191 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002192 return -1;
2193}
2194
2195/* choice default */
2196int
2197resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2198{
2199 /* cannot actually be a path */
2200 if (strchr(nodeid, '/')) {
2201 return -1;
2202 }
2203
Michal Vaskodc300b02017-04-07 14:09:20 +02002204 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002205}
2206
2207/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2208static int
2209resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2210{
2211 const struct lys_module *module;
2212 const char *mod_prefix, *name;
2213 int i, mod_prefix_len, nam_len;
2214
2215 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002216 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 +01002217 return -i + 1;
2218 }
2219
Michal Vasko921eb6b2017-10-13 10:01:39 +02002220 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002221 if (!module) {
2222 return -1;
2223 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002224 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002225 start = module->data;
2226 }
2227
2228 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2229
2230 return EXIT_SUCCESS;
2231}
2232
2233int
2234resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2235 const struct lys_node **ret)
2236{
2237 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002238 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002239 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002240 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002241
2242 assert(nodeid && module && ret);
2243 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2244
2245 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002246 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002247
Michal Vasko50576712017-07-28 12:28:33 +02002248 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 +01002249 return ((id - nodeid) - r) + 1;
2250 }
2251 id += r;
2252
2253 if (is_relative) {
2254 return -1;
2255 }
2256
Michal Vasko921eb6b2017-10-13 10:01:39 +02002257 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01002258 if (!abs_start_mod) {
2259 return -1;
2260 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002261
2262 while (1) {
2263 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002264 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vaskocb45f472018-02-12 10:47:42 +01002265 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002266 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2267 if (r == 0) {
2268 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002269 if (!(sibling->nodetype & ret_nodetype)) {
2270 /* wrong node type, too bad */
2271 continue;
2272 }
2273 *ret = sibling;
2274 return EXIT_SUCCESS;
2275 }
Michal Vasko50576712017-07-28 12:28:33 +02002276 start_parent = sibling;
2277 break;
2278 } else if (r == 1) {
2279 continue;
2280 } else {
2281 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002282 }
2283 }
2284
2285 /* no match */
2286 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002287 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002288 return EXIT_SUCCESS;
2289 }
2290
Michal Vasko50576712017-07-28 12:28:33 +02002291 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 +01002292 return ((id - nodeid) - r) + 1;
2293 }
2294 id += r;
2295 }
2296
2297 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002298 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002299 return -1;
2300}
2301
Michal Vaskoe733d682016-03-14 09:08:27 +01002302static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002303resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002304{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002305 const char *mod_name, *name;
2306 int mod_name_len, nam_len, has_predicate, i;
2307 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002308
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002309 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 +02002310 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002311 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002312 return -1;
2313 }
2314
2315 predicate += i;
2316 *parsed += i;
2317
Michal Vasko58c2aab2017-01-05 10:02:05 +01002318 if (!isdigit(name[0])) {
2319 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002320 key = (struct lys_node *)list->keys[i];
2321 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002322 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002323 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002324 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002325
Michal Vasko58c2aab2017-01-05 10:02:05 +01002326 if (i == list->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002327 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko58c2aab2017-01-05 10:02:05 +01002328 return -1;
2329 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002330 }
2331
2332 /* more predicates? */
2333 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002334 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002335 }
2336
2337 return 0;
2338}
2339
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002340/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002341const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002342resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002343{
Michal Vasko53b7da02018-02-13 15:28:42 +01002344 char *str;
PavolVicanb28bbff2018-02-21 00:44:02 +01002345 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vaskob3744402017-08-03 14:23:58 +02002346 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002347 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
PavolVicanb28bbff2018-02-21 00:44:02 +01002348 int yang_data_name_len, backup_mod_name_len;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002349 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002350 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002351
Michal Vasko3547c532016-03-14 09:40:50 +01002352 assert(nodeid && (ctx || start));
2353 if (!ctx) {
2354 ctx = start->module->ctx;
2355 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002356
2357 id = nodeid;
2358
PavolVican195cf392018-02-23 13:24:45 +01002359 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 +01002360 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2361 return NULL;
2362 }
2363
2364 if (name[0] == '#') {
2365 if (is_relative) {
2366 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2367 return NULL;
2368 }
2369 yang_data_name = name + 1;
2370 yang_data_name_len = nam_len - 1;
2371 backup_mod_name = mod_name;
2372 backup_mod_name_len = mod_name_len;
2373 id += r;
2374 } else {
2375 is_relative = -1;
2376 }
2377
Michal Vasko50576712017-07-28 12:28:33 +02002378 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 +01002379 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002380 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002381 }
2382 id += r;
2383
PavolVicanb28bbff2018-02-21 00:44:02 +01002384 if (backup_mod_name) {
2385 mod_name = backup_mod_name;
2386 mod_name_len = backup_mod_name_len;
2387 }
2388
Michal Vasko3edeaf72016-02-11 13:17:43 +01002389 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002390 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002391 start_parent = start;
2392 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2393 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002394 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002395 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002396 } else {
2397 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002398 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002399 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
Michal Vasko10728b52016-04-07 14:26:29 +02002400 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002401 return NULL;
2402 }
2403
Michal Vasko53b7da02018-02-13 15:28:42 +01002404 str = strndup(mod_name, mod_name_len);
2405 module = ly_ctx_get_module(ctx, str, NULL, 1);
2406 free(str);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002407
Michal Vaskof68a49e2017-08-14 13:23:37 +02002408 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002409 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002410 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002411 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002412 return NULL;
2413 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002414 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01002415 if (yang_data_name) {
2416 start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2417 if (!start_parent) {
2418 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2419 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2420 free(str);
2421 return NULL;
2422 }
2423 }
Michal Vasko3547c532016-03-14 09:40:50 +01002424
2425 /* now it's as if there was no module name */
2426 mod_name = NULL;
2427 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002428 }
2429
Michal Vaskof68a49e2017-08-14 13:23:37 +02002430 prev_mod = module;
2431
Michal Vasko3edeaf72016-02-11 13:17:43 +01002432 while (1) {
2433 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002434 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002435 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002436 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002437 /* output check */
2438 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2439 if (parent) {
2440 if (output && (parent->nodetype == LYS_INPUT)) {
2441 continue;
2442 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2443 continue;
2444 }
2445 }
2446
Michal Vasko3edeaf72016-02-11 13:17:43 +01002447 /* module check */
2448 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002449 /* will also find an augment module */
Michal Vasko53b7da02018-02-13 15:28:42 +01002450 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002451
Michal Vasko3edeaf72016-02-11 13:17:43 +01002452 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002453 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002454 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002455 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002456 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002457 }
2458 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002459 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002460 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002461 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002462 continue;
2463 }
2464
Michal Vaskoe733d682016-03-14 09:08:27 +01002465 /* do we have some predicates on it? */
2466 if (has_predicate) {
2467 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002468 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002469 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002470 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002471 return NULL;
2472 }
2473 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002474 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002475 return NULL;
2476 }
2477 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002478 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002479 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002480 }
2481 id += r;
2482 }
2483
Michal Vasko3edeaf72016-02-11 13:17:43 +01002484 /* the result node? */
2485 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002486 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002487 }
2488
Michal Vaskodc300b02017-04-07 14:09:20 +02002489 /* move down the tree, if possible */
2490 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002491 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskodc300b02017-04-07 14:09:20 +02002492 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002493 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002494 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002495
2496 /* update prev mod */
2497 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002498 break;
2499 }
2500 }
2501
2502 /* no match */
2503 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002504 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002505 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002506 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002507 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002508 }
2509
Michal Vasko50576712017-07-28 12:28:33 +02002510 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 +01002511 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002512 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002513 }
2514 id += r;
2515 }
2516
2517 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002518 LOGINT(ctx);
Michal Vaskoe733d682016-03-14 09:08:27 +01002519 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002520}
2521
Michal Vasko22448d32016-03-16 13:17:29 +01002522static int
Michal Vasko2d44ee02018-05-18 09:38:51 +02002523resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
Michal Vasko22448d32016-03-16 13:17:29 +01002524{
Michal Vaskofebd13d2018-05-17 10:42:24 +02002525 const char *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002526 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002527 struct lyd_node_leaf_list *key;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002528 struct lys_node_list *slist;
Michal Vasko53b7da02018-02-13 15:28:42 +01002529 struct ly_ctx *ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002530
Radek Krejci61a86c62016-03-24 11:06:44 +01002531 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002532 assert(node->schema->nodetype == LYS_LIST);
Michal Vasko2d44ee02018-05-18 09:38:51 +02002533 assert(pp.len);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002534
Michal Vasko53b7da02018-02-13 15:28:42 +01002535 ctx = node->schema->module->ctx;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002536 slist = (struct lys_node_list *)node->schema;
Michal Vasko22448d32016-03-16 13:17:29 +01002537
Michal Vasko53adfc72017-01-06 10:39:10 +01002538 /* is the predicate a number? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002539 if (isdigit(pp.pred[0].name[0])) {
2540 if (position == atoi(pp.pred[0].name)) {
Michal Vasko53adfc72017-01-06 10:39:10 +01002541 /* match */
Michal Vasko53adfc72017-01-06 10:39:10 +01002542 return 0;
2543 } else {
2544 /* not a match */
2545 return 1;
2546 }
2547 }
2548
Michal Vaskofebd13d2018-05-17 10:42:24 +02002549 /* basic checks */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002550 if (pp.len > slist->keys_size) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002551 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2552 return -1;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002553 } else if (pp.len < slist->keys_size) {
2554 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp.len]->name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002555 return -1;
Michal Vasko53adfc72017-01-06 10:39:10 +01002556 }
2557
Michal Vaskof29903d2016-04-18 13:13:10 +02002558 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002559 if (!key) {
2560 /* it is not a position, so we need a key for it to be a match */
2561 return 1;
2562 }
2563
2564 /* go through all the keys */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002565 for (i = 0; i < slist->keys_size; ++i) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002566 if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
2567 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002568 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002569 }
2570
Michal Vasko2d44ee02018-05-18 09:38:51 +02002571 if (pp.pred[i].mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002572 /* specific module, check that the found key is from that module */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002573 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
2574 || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
2575 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002576 return -1;
2577 }
Michal Vasko50576712017-07-28 12:28:33 +02002578
2579 /* but if the module is the same as the parent, it should have been omitted */
2580 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002581 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko50576712017-07-28 12:28:33 +02002582 return -1;
2583 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002584 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002585 /* no module, so it must be the same as the list (parent) */
2586 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002587 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002588 return -1;
2589 }
2590 }
2591
Michal Vasko9ba34de2016-12-07 12:21:19 +01002592 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002593 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002594 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2595 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002596 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2597 } else {
2598 key_val = key->value_str;
2599 }
2600
Michal Vasko22448d32016-03-16 13:17:29 +01002601 /* value does not match */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002602 if (strncmp(key_val, pp.pred[i].value, pp.pred[i].val_len) || key_val[pp.pred[i].val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002603 return 1;
2604 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002605
2606 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002607 }
2608
Michal Vasko22448d32016-03-16 13:17:29 +01002609 return 0;
2610}
2611
Radek Krejci45826012016-08-24 15:07:57 +02002612/**
2613 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2614 *
2615 * @param[in] nodeid Node data path to find
2616 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2617 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2618 * @param[out] parsed Number of characters processed in \p id
2619 * @return The closes parent (or the node itself) from the path
2620 */
Michal Vasko22448d32016-03-16 13:17:29 +01002621struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002622resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2623 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002624{
Michal Vasko2d44ee02018-05-18 09:38:51 +02002625 const char *id, *mod_name, *name, *data_val, *llval;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002626 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002627 int has_predicate, last_parsed = 0, llval_len;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002628 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002629 struct lyd_node_leaf_list *llist;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002630 const struct lys_module *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002631 struct ly_ctx *ctx;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002632 const struct lys_node *ssibling;
2633 struct parsed_pred pp;
Michal Vasko22448d32016-03-16 13:17:29 +01002634
2635 assert(nodeid && start && parsed);
2636
Michal Vasko2d44ee02018-05-18 09:38:51 +02002637 memset(&pp, 0, sizeof pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002638 ctx = start->schema->module->ctx;
2639 id = nodeid;
2640
Michal Vasko2d44ee02018-05-18 09:38:51 +02002641 /* parse first nodeid in case it is yang-data extension */
PavolVican195cf392018-02-23 13:24:45 +01002642 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 +01002643 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002644 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002645 }
2646
2647 if (name[0] == '#') {
2648 if (is_relative) {
2649 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002650 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002651 }
PavolVicanb28bbff2018-02-21 00:44:02 +01002652 id += r;
2653 last_parsed = r;
2654 } else {
2655 is_relative = -1;
2656 }
2657
Michal Vasko2d44ee02018-05-18 09:38:51 +02002658 /* parse first nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002659 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 +01002660 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002661 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002662 }
2663 id += r;
2664 /* add it to parsed only after the data node was actually found */
PavolVicanb28bbff2018-02-21 00:44:02 +01002665 last_parsed += r;
Michal Vasko22448d32016-03-16 13:17:29 +01002666
2667 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002668 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002669 start = start->child;
2670 } else {
2671 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002672 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002673 }
2674
Michal Vaskofebd13d2018-05-17 10:42:24 +02002675 /* do not duplicate code, use predicate parsing from the loop */
2676 goto parse_predicates;
2677
Michal Vasko22448d32016-03-16 13:17:29 +01002678 while (1) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002679 /* find the correct schema node first */
2680 ssibling = NULL;
2681 while ((ssibling = lys_getnext(ssibling, (start && start->parent) ? start->parent->schema : NULL, prev_mod, 0))) {
2682 if (!schema_nodeid_siblingcheck(ssibling, prev_mod, mod_name, mod_name_len, name, nam_len)) {
2683 break;
Michal Vasko2411b942016-03-23 13:50:03 +01002684 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002685 }
2686 if (!ssibling) {
2687 /* there is not even such a schema node */
2688 free(pp.pred);
2689 return last_match;
2690 }
2691 pp.schema = ssibling;
Michal Vasko2411b942016-03-23 13:50:03 +01002692
Michal Vasko2d44ee02018-05-18 09:38:51 +02002693 /* unify leaf-list value - it is possible to specify last-node value as both a predicate or parameter if
2694 * is a leaf-list, unify both cases and the value will in both cases be in the predicate structure */
2695 if (!id[0] && !pp.len && (ssibling->nodetype == LYS_LEAFLIST)) {
2696 pp.len = 1;
2697 pp.pred = calloc(1, sizeof *pp.pred);
2698 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
Michal Vasko22448d32016-03-16 13:17:29 +01002699
Michal Vasko2d44ee02018-05-18 09:38:51 +02002700 pp.pred[0].name = ".";
2701 pp.pred[0].nam_len = 1;
2702 pp.pred[0].value = (llist_value ? llist_value : "");
2703 pp.pred[0].val_len = strlen(pp.pred[0].value);
2704 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002705
Michal Vasko2d44ee02018-05-18 09:38:51 +02002706 if (ssibling->nodetype == LYS_LEAFLIST) {
2707 /* check leaf-list predicate */
2708 if (pp.len > 1) {
2709 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2710 goto error;
2711 }
2712 if ((pp.pred[0].name[0] != '.') || (pp.pred[0].nam_len != 1)) {
2713 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp.pred[0].name[0], pp.pred[0].name);
2714 goto error;
2715 }
2716 } else if (ssibling->nodetype == LYS_LIST) {
2717 /* list should have predicates */
2718 if (!pp.len) {
2719 /* none match */
2720 return last_match;
2721 }
2722 } else if (pp.pred) {
2723 /* no other nodes allow predicates */
2724 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2725 goto error;
2726 }
2727
2728#ifdef LY_ENABLED_CACHE
2729 /* we will not be matching keyless lists or state leaf-lists this way */
2730 if (start->parent && start->parent->ht && ((pp.schema->nodetype != LYS_LIST) || ((struct lys_node_list *)pp.schema)->keys_size)
2731 && ((pp.schema->nodetype != LYS_LEAFLIST) || (pp.schema->flags & LYS_CONFIG_W))) {
2732 sibling = resolve_json_data_node_hash(start->parent, pp);
2733 } else
2734#endif
2735 {
2736 list_instance_position = 0;
2737 LY_TREE_FOR(start, sibling) {
2738 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
2739 if (lys_parent(sibling->schema)) {
2740 if (options & LYD_PATH_OPT_OUTPUT) {
2741 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
2742 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
2743 goto error;
2744 }
2745 } else {
2746 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
2747 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
2748 goto error;
2749 }
Michal Vasko22448d32016-03-16 13:17:29 +01002750 }
Michal Vasko22448d32016-03-16 13:17:29 +01002751 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002752
2753 if (sibling->schema != ssibling) {
2754 /* wrong schema node */
Michal Vasko22448d32016-03-16 13:17:29 +01002755 continue;
2756 }
2757
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002758 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002759 if (ssibling->nodetype == LYS_LEAFLIST) {
2760 if (ssibling->flags & LYS_CONFIG_R) {
Michal Vasko24affa02018-04-03 09:06:06 +02002761 /* state leaf-lists will never match */
2762 continue;
2763 }
2764
Michal Vasko9ba34de2016-12-07 12:21:19 +01002765 llist = (struct lyd_node_leaf_list *)sibling;
2766
Michal Vasko2d44ee02018-05-18 09:38:51 +02002767 /* get the expected leaf-list value */
2768 llval = NULL;
2769 llval_len = 0;
2770 if (pp.pred) {
2771 /* it was already checked that it is correct */
2772 llval = pp.pred[0].value;
2773 llval_len = pp.pred[0].val_len;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002774
Michal Vaskof0a50972016-10-19 11:33:55 +02002775 }
2776
Michal Vasko21b90ce2017-09-19 09:38:27 +02002777 /* make value canonical (remove module name prefix) unless it was specified with it */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002778 if (llval && !strchr(llval, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002779 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2780 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002781 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2782 } else {
2783 data_val = llist->value_str;
2784 }
2785
Michal Vasko2d44ee02018-05-18 09:38:51 +02002786 if ((!llval && data_val && data_val[0]) || (llval && (strncmp(llval, data_val, llval_len)
2787 || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002788 continue;
2789 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002790
Michal Vasko2d44ee02018-05-18 09:38:51 +02002791 } else if (ssibling->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002792 /* 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 +01002793 ++list_instance_position;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002794 ret = resolve_partial_json_data_list_predicate(pp, sibling, list_instance_position);
Michal Vasko22448d32016-03-16 13:17:29 +01002795 if (ret == -1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002796 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002797 } else if (ret == 1) {
2798 /* this list instance does not match */
2799 continue;
2800 }
Michal Vasko22448d32016-03-16 13:17:29 +01002801 }
2802
Michal Vasko22448d32016-03-16 13:17:29 +01002803 break;
2804 }
2805 }
2806
2807 /* no match, return last match */
2808 if (!sibling) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002809 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002810 return last_match;
2811 }
2812
Michal Vasko2d44ee02018-05-18 09:38:51 +02002813 /* we found a next matching node */
2814 *parsed += last_parsed;
2815
2816 /* the result node? */
2817 if (!id[0]) {
2818 free(pp.pred);
2819 return sibling;
2820 }
2821
2822 /* move down the tree, if possible */
2823 if (ssibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2824 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2825 goto error;
2826 }
2827 last_match = sibling;
2828 prev_mod = lyd_node_module(sibling);
2829 start = sibling->child;
2830
Michal Vaskofebd13d2018-05-17 10:42:24 +02002831 /* parse nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002832 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 +01002833 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002834 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002835 }
2836 id += r;
2837 last_parsed = r;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002838
2839parse_predicates:
2840 /* parse all the predicates */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002841 free(pp.pred);
2842 pp.schema = NULL;
2843 pp.len = 0;
2844 pp.pred = NULL;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002845 while (has_predicate) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002846 ++pp.len;
2847 pp.pred = ly_realloc(pp.pred, pp.len * sizeof *pp.pred);
2848 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2849 if ((r = parse_schema_json_predicate(id, &pp.pred[pp.len - 1].mod_name, &pp.pred[pp.len - 1].mod_name_len,
2850 &pp.pred[pp.len - 1].name, &pp.pred[pp.len - 1].nam_len, &pp.pred[pp.len - 1].value,
2851 &pp.pred[pp.len - 1].val_len, &has_predicate)) < 1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002852 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2853 goto error;
2854 }
2855
2856 id += r;
2857 last_parsed += r;
2858 }
Michal Vasko22448d32016-03-16 13:17:29 +01002859 }
2860
Michal Vaskofebd13d2018-05-17 10:42:24 +02002861error:
Michal Vasko238bd2f2016-03-23 09:39:01 +01002862 *parsed = -1;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002863 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002864 return NULL;
2865}
2866
Michal Vasko3edeaf72016-02-11 13:17:43 +01002867/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002868 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002869 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002870 *
Michal Vasko53b7da02018-02-13 15:28:42 +01002871 * @param[in] ctx Context for errors.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002872 * @param[in] str_restr Restriction as a string.
2873 * @param[in] type Type of the restriction.
2874 * @param[out] ret Final interval structure that starts with
2875 * the interval of the initial type, continues with intervals
2876 * of any superior types derived from the initial one, and
2877 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002878 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002879 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002880 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002881int
Michal Vasko53b7da02018-02-13 15:28:42 +01002882resolve_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 +02002883{
2884 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002885 int kind;
Michal Vaskof75b2772018-03-14 09:55:33 +01002886 int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2887 uint64_t local_umin, local_umax = 0;
2888 uint8_t local_fdig = 0;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002889 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002890 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002891
2892 switch (type->base) {
2893 case LY_TYPE_BINARY:
2894 kind = 0;
2895 local_umin = 0;
2896 local_umax = 18446744073709551615UL;
2897
2898 if (!str_restr && type->info.binary.length) {
2899 str_restr = type->info.binary.length->expr;
2900 }
2901 break;
2902 case LY_TYPE_DEC64:
2903 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002904 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2905 local_fmax = __INT64_C(9223372036854775807);
2906 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002907
2908 if (!str_restr && type->info.dec64.range) {
2909 str_restr = type->info.dec64.range->expr;
2910 }
2911 break;
2912 case LY_TYPE_INT8:
2913 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002914 local_smin = __INT64_C(-128);
2915 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002916
2917 if (!str_restr && type->info.num.range) {
2918 str_restr = type->info.num.range->expr;
2919 }
2920 break;
2921 case LY_TYPE_INT16:
2922 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002923 local_smin = __INT64_C(-32768);
2924 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002925
2926 if (!str_restr && type->info.num.range) {
2927 str_restr = type->info.num.range->expr;
2928 }
2929 break;
2930 case LY_TYPE_INT32:
2931 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002932 local_smin = __INT64_C(-2147483648);
2933 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002934
2935 if (!str_restr && type->info.num.range) {
2936 str_restr = type->info.num.range->expr;
2937 }
2938 break;
2939 case LY_TYPE_INT64:
2940 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002941 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2942 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002943
2944 if (!str_restr && type->info.num.range) {
2945 str_restr = type->info.num.range->expr;
2946 }
2947 break;
2948 case LY_TYPE_UINT8:
2949 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002950 local_umin = __UINT64_C(0);
2951 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002952
2953 if (!str_restr && type->info.num.range) {
2954 str_restr = type->info.num.range->expr;
2955 }
2956 break;
2957 case LY_TYPE_UINT16:
2958 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002959 local_umin = __UINT64_C(0);
2960 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002961
2962 if (!str_restr && type->info.num.range) {
2963 str_restr = type->info.num.range->expr;
2964 }
2965 break;
2966 case LY_TYPE_UINT32:
2967 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002968 local_umin = __UINT64_C(0);
2969 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002970
2971 if (!str_restr && type->info.num.range) {
2972 str_restr = type->info.num.range->expr;
2973 }
2974 break;
2975 case LY_TYPE_UINT64:
2976 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002977 local_umin = __UINT64_C(0);
2978 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002979
2980 if (!str_restr && type->info.num.range) {
2981 str_restr = type->info.num.range->expr;
2982 }
2983 break;
2984 case LY_TYPE_STRING:
2985 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002986 local_umin = __UINT64_C(0);
2987 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002988
2989 if (!str_restr && type->info.str.length) {
2990 str_restr = type->info.str.length->expr;
2991 }
2992 break;
2993 default:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002994 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002995 }
2996
2997 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002998 if (type->der) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002999 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003000 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02003001 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003002 assert(!intv || (intv->kind == kind));
3003 }
3004
3005 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003006 /* we do not have any restriction, return superior ones */
3007 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003008 return EXIT_SUCCESS;
3009 }
3010
3011 /* adjust local min and max */
3012 if (intv) {
3013 tmp_intv = intv;
3014
3015 if (kind == 0) {
3016 local_umin = tmp_intv->value.uval.min;
3017 } else if (kind == 1) {
3018 local_smin = tmp_intv->value.sval.min;
3019 } else if (kind == 2) {
3020 local_fmin = tmp_intv->value.fval.min;
3021 }
3022
3023 while (tmp_intv->next) {
3024 tmp_intv = tmp_intv->next;
3025 }
3026
3027 if (kind == 0) {
3028 local_umax = tmp_intv->value.uval.max;
3029 } else if (kind == 1) {
3030 local_smax = tmp_intv->value.sval.max;
3031 } else if (kind == 2) {
3032 local_fmax = tmp_intv->value.fval.max;
3033 }
3034 }
3035
3036 /* finally parse our restriction */
3037 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003038 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003039 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003040 if (!tmp_local_intv) {
3041 assert(!local_intv);
3042 local_intv = malloc(sizeof *local_intv);
3043 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003044 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003045 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003046 tmp_local_intv = tmp_local_intv->next;
3047 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003048 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003049
3050 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003051 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003052 tmp_local_intv->next = NULL;
3053
3054 /* min */
3055 ptr = seg_ptr;
3056 while (isspace(ptr[0])) {
3057 ++ptr;
3058 }
3059 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3060 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02003061 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003062 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003063 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003064 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003065 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003066 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003067 goto error;
3068 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003069 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003070 } else if (!strncmp(ptr, "min", 3)) {
3071 if (kind == 0) {
3072 tmp_local_intv->value.uval.min = local_umin;
3073 } else if (kind == 1) {
3074 tmp_local_intv->value.sval.min = local_smin;
3075 } else if (kind == 2) {
3076 tmp_local_intv->value.fval.min = local_fmin;
3077 }
3078
3079 ptr += 3;
3080 } else if (!strncmp(ptr, "max", 3)) {
3081 if (kind == 0) {
3082 tmp_local_intv->value.uval.min = local_umax;
3083 } else if (kind == 1) {
3084 tmp_local_intv->value.sval.min = local_smax;
3085 } else if (kind == 2) {
3086 tmp_local_intv->value.fval.min = local_fmax;
3087 }
3088
3089 ptr += 3;
3090 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003091 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003092 }
3093
3094 while (isspace(ptr[0])) {
3095 ptr++;
3096 }
3097
3098 /* no interval or interval */
3099 if ((ptr[0] == '|') || !ptr[0]) {
3100 if (kind == 0) {
3101 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
3102 } else if (kind == 1) {
3103 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
3104 } else if (kind == 2) {
3105 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
3106 }
3107 } else if (!strncmp(ptr, "..", 2)) {
3108 /* skip ".." */
3109 ptr += 2;
3110 while (isspace(ptr[0])) {
3111 ++ptr;
3112 }
3113
3114 /* max */
3115 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3116 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02003117 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003118 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003119 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003120 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003121 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003122 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003123 goto error;
3124 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003125 }
3126 } else if (!strncmp(ptr, "max", 3)) {
3127 if (kind == 0) {
3128 tmp_local_intv->value.uval.max = local_umax;
3129 } else if (kind == 1) {
3130 tmp_local_intv->value.sval.max = local_smax;
3131 } else if (kind == 2) {
3132 tmp_local_intv->value.fval.max = local_fmax;
3133 }
3134 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003135 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003136 }
3137 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003138 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003139 }
3140
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003141 /* check min and max in correct order*/
3142 if (kind == 0) {
3143 /* current segment */
3144 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
3145 goto error;
3146 }
3147 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
3148 goto error;
3149 }
3150 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02003151 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003152 goto error;
3153 }
3154 } else if (kind == 1) {
3155 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3156 goto error;
3157 }
3158 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3159 goto error;
3160 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003161 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003162 goto error;
3163 }
3164 } else if (kind == 2) {
3165 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3166 goto error;
3167 }
3168 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3169 goto error;
3170 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003171 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003172 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003173 goto error;
3174 }
3175 }
3176
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003177 /* next segment (next OR) */
3178 seg_ptr = strchr(seg_ptr, '|');
3179 if (!seg_ptr) {
3180 break;
3181 }
3182 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003183 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003184 }
3185
3186 /* check local restrictions against superior ones */
3187 if (intv) {
3188 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003189 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003190
3191 while (tmp_local_intv && tmp_intv) {
3192 /* reuse local variables */
3193 if (kind == 0) {
3194 local_umin = tmp_local_intv->value.uval.min;
3195 local_umax = tmp_local_intv->value.uval.max;
3196
3197 /* it must be in this interval */
3198 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3199 /* this interval is covered, next one */
3200 if (local_umax <= tmp_intv->value.uval.max) {
3201 tmp_local_intv = tmp_local_intv->next;
3202 continue;
3203 /* ascending order of restrictions -> fail */
3204 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003205 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003206 }
3207 }
3208 } else if (kind == 1) {
3209 local_smin = tmp_local_intv->value.sval.min;
3210 local_smax = tmp_local_intv->value.sval.max;
3211
3212 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3213 if (local_smax <= tmp_intv->value.sval.max) {
3214 tmp_local_intv = tmp_local_intv->next;
3215 continue;
3216 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003217 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003218 }
3219 }
3220 } else if (kind == 2) {
3221 local_fmin = tmp_local_intv->value.fval.min;
3222 local_fmax = tmp_local_intv->value.fval.max;
3223
Michal Vasko4d1f0482016-09-19 14:35:06 +02003224 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003225 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003226 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003227 tmp_local_intv = tmp_local_intv->next;
3228 continue;
3229 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003230 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003231 }
3232 }
3233 }
3234
3235 tmp_intv = tmp_intv->next;
3236 }
3237
3238 /* some interval left uncovered -> fail */
3239 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003240 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003241 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003242 }
3243
Michal Vaskoaeb51802016-04-11 10:58:47 +02003244 /* append the local intervals to all the intervals of the superior types, return it all */
3245 if (intv) {
3246 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3247 tmp_intv->next = local_intv;
3248 } else {
3249 intv = local_intv;
3250 }
3251 *ret = intv;
3252
3253 return EXIT_SUCCESS;
3254
3255error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003256 while (intv) {
3257 tmp_intv = intv->next;
3258 free(intv);
3259 intv = tmp_intv;
3260 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003261 while (local_intv) {
3262 tmp_local_intv = local_intv->next;
3263 free(local_intv);
3264 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003265 }
3266
Michal Vaskoaeb51802016-04-11 10:58:47 +02003267 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003268}
3269
Michal Vasko730dfdf2015-08-11 14:48:05 +02003270/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003271 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3272 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003273 *
3274 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003275 * @param[in] mod_name Typedef name module name.
3276 * @param[in] module Main module.
3277 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003278 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003279 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003280 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003281 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003282int
Michal Vasko1e62a092015-12-01 12:27:20 +01003283resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3284 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003285{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003286 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003287 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003288 int tpdf_size;
3289
Michal Vasko1dca6882015-10-22 14:29:42 +02003290 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003291 /* no prefix, try built-in types */
3292 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003293 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003294 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003295 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003296 }
3297 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003298 }
3299 }
3300 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003301 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003302 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003303 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003304 }
3305 }
3306
Michal Vasko1dca6882015-10-22 14:29:42 +02003307 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003308 /* search in local typedefs */
3309 while (parent) {
3310 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003311 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003312 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3313 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003314 break;
3315
Radek Krejci76512572015-08-04 09:47:08 +02003316 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003317 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3318 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003319 break;
3320
Radek Krejci76512572015-08-04 09:47:08 +02003321 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003322 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3323 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003324 break;
3325
Radek Krejci76512572015-08-04 09:47:08 +02003326 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003327 case LYS_ACTION:
3328 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3329 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003330 break;
3331
Radek Krejci76512572015-08-04 09:47:08 +02003332 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003333 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3334 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003335 break;
3336
Radek Krejci76512572015-08-04 09:47:08 +02003337 case LYS_INPUT:
3338 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003339 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3340 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003341 break;
3342
3343 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003344 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003345 continue;
3346 }
3347
3348 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003349 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003350 match = &tpdf[i];
3351 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003352 }
3353 }
3354
Michal Vaskodcf98e62016-05-05 17:53:53 +02003355 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003356 }
Radek Krejcic071c542016-01-27 14:57:51 +01003357 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003358 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003359 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003360 if (!module) {
3361 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003362 }
3363 }
3364
3365 /* search in top level typedefs */
3366 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003367 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003368 match = &module->tpdf[i];
3369 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003370 }
3371 }
3372
3373 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003374 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003375 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003376 if (!strcmp(module->inc[i].submodule->tpdf[j].name, name) && module->inc[i].submodule->tpdf[j].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003377 match = &module->inc[i].submodule->tpdf[j];
3378 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 }
3380 }
3381 }
3382
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003383 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003384
3385check_leafref:
3386 if (ret) {
3387 *ret = match;
3388 }
3389 if (match->type.base == LY_TYPE_LEAFREF) {
3390 while (!match->type.info.lref.path) {
3391 match = match->type.der;
3392 assert(match);
3393 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003394 }
3395 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003396}
3397
Michal Vasko1dca6882015-10-22 14:29:42 +02003398/**
3399 * @brief Check the default \p value of the \p type. Logs directly.
3400 *
3401 * @param[in] type Type definition to use.
3402 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003403 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003404 *
3405 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3406 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003407static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003408check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409{
Radek Krejcibad2f172016-08-02 11:04:15 +02003410 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003411 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003412 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003413 char *s;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003414 int ret = EXIT_SUCCESS, r;
Michal Vasko53b7da02018-02-13 15:28:42 +01003415 struct ly_ctx *ctx = module->ctx;
Michal Vasko1dca6882015-10-22 14:29:42 +02003416
Radek Krejci51673202016-11-01 17:00:32 +01003417 assert(value);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003418 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003419
Radek Krejcic13db382016-08-16 10:52:42 +02003420 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003421 /* the type was not resolved yet, nothing to do for now */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003422 ret = EXIT_FAILURE;
3423 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003424 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003425 /* do not check defaults in not implemented module's data */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003426 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003427 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003428 /* identityrefs are checked when instantiated in data instead of typedef,
3429 * but in typedef the value has to be modified to include the prefix */
3430 if (*value) {
3431 if (strchr(*value, ':')) {
3432 dflt = transform_schema2json(module, *value);
3433 } else {
3434 /* default prefix of the module where the typedef is defined */
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003435 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3436 LOGMEM(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003437 ret = -1;
3438 goto cleanup;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003439 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003440 dflt = lydict_insert_zc(ctx, s);
Radek Krejci9e6af732017-04-27 14:40:25 +02003441 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003442 lydict_remove(ctx, *value);
Radek Krejci9e6af732017-04-27 14:40:25 +02003443 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003444 dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003445 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003446 goto cleanup;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003447 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3448 /* leafref in typedef cannot be checked */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003449 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003450 }
3451
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003452 dflt = lydict_insert(ctx, *value, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003453 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003454 /* we do not have a new default value, so is there any to check even, in some base type? */
3455 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3456 if (base_tpdf->dflt) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003457 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
Michal Vasko478c4652016-07-21 12:55:01 +02003458 break;
3459 }
3460 }
3461
Radek Krejci51673202016-11-01 17:00:32 +01003462 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003463 /* no default value, nothing to check, all is well */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003464 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003465 }
3466
3467 /* 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)? */
3468 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003469 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003470 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003471 goto cleanup;
Radek Krejci9e6af732017-04-27 14:40:25 +02003472 } else {
3473 /* check the default value from typedef, but use also the typedef's module
3474 * due to possible searching in imported modules which is expected in
3475 * typedef's module instead of module where the typedef is used */
3476 module = base_tpdf->module;
3477 }
3478 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003479 case LY_TYPE_INST:
3480 case LY_TYPE_LEAFREF:
3481 case LY_TYPE_BOOL:
3482 case LY_TYPE_EMPTY:
3483 /* 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 +01003484 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003485 case LY_TYPE_BITS:
3486 /* the default value must match the restricted list of values, if the type was restricted */
3487 if (type->info.bits.count) {
3488 break;
3489 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003490 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003491 case LY_TYPE_ENUM:
3492 /* the default value must match the restricted list of values, if the type was restricted */
3493 if (type->info.enums.count) {
3494 break;
3495 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003496 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003497 case LY_TYPE_DEC64:
3498 if (type->info.dec64.range) {
3499 break;
3500 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003501 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003502 case LY_TYPE_BINARY:
3503 if (type->info.binary.length) {
3504 break;
3505 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003506 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003507 case LY_TYPE_INT8:
3508 case LY_TYPE_INT16:
3509 case LY_TYPE_INT32:
3510 case LY_TYPE_INT64:
3511 case LY_TYPE_UINT8:
3512 case LY_TYPE_UINT16:
3513 case LY_TYPE_UINT32:
3514 case LY_TYPE_UINT64:
3515 if (type->info.num.range) {
3516 break;
3517 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003518 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003519 case LY_TYPE_STRING:
3520 if (type->info.str.length || type->info.str.patterns) {
3521 break;
3522 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003523 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003524 case LY_TYPE_UNION:
3525 /* way too much trouble learning whether we need to check the default again, so just do it */
3526 break;
3527 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01003528 LOGINT(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003529 ret = -1;
3530 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003531 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003532 } else if (type->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003533 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3534 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003535 ret = -1;
3536 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003537 }
3538
Michal Vasko1dca6882015-10-22 14:29:42 +02003539 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003540 memset(&node, 0, sizeof node);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003541 node.value_str = lydict_insert(ctx, dflt, 0);
Michal Vasko1dca6882015-10-22 14:29:42 +02003542 node.value_type = type->base;
Michal Vasko31a2d322018-01-12 13:36:12 +01003543
3544 if (tpdf) {
3545 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003546 if (!node.schema) {
3547 LOGMEM(ctx);
3548 ret = -1;
3549 goto cleanup;
3550 }
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003551 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003552 if (r == -1) {
3553 LOGMEM(ctx);
3554 ret = -1;
3555 goto cleanup;
3556 }
Michal Vasko31a2d322018-01-12 13:36:12 +01003557 node.schema->module = module;
3558 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3559 } else {
3560 node.schema = (struct lys_node *)type->parent;
3561 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003562
Radek Krejci37b756f2016-01-18 10:15:03 +01003563 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003564 if (!type->info.lref.target) {
3565 ret = EXIT_FAILURE;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003566 goto cleanup;
Michal Vasko1dca6882015-10-22 14:29:42 +02003567 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003568 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003569 if (!ret) {
3570 /* adopt possibly changed default value to its canonical form */
3571 if (*value) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003572 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003573 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003574 dflt = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003575 }
3576 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003577 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01003578 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003579 /* possible forward reference */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003580 ret = EXIT_FAILURE;
Radek Krejcibad2f172016-08-02 11:04:15 +02003581 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003582 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003583 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3584 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3585 /* we have refined bits/enums */
Michal Vasko53b7da02018-02-13 15:28:42 +01003586 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
Radek Krejcibad2f172016-08-02 11:04:15 +02003587 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003588 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003589 }
3590 }
Radek Krejci51673202016-11-01 17:00:32 +01003591 } else {
3592 /* success - adopt canonical form from the node into the default value */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003593 if (!ly_strequal(dflt, node.value_str, 1)) {
Radek Krejci51673202016-11-01 17:00:32 +01003594 /* this can happen only if we have non-inherited default value,
3595 * inherited default values are already in canonical form */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003596 assert(ly_strequal(dflt, *value, 1));
3597
3598 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003599 *value = node.value_str;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003600 node.value_str = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003601 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003602 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003603 }
3604
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003605cleanup:
Michal Vasko70bf8e52018-03-26 11:32:33 +02003606 lyd_free_value(node.value, node.value_type, node.value_flags, type);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003607 lydict_remove(ctx, node.value_str);
3608 if (tpdf && node.schema) {
Michal Vasko31a2d322018-01-12 13:36:12 +01003609 free((char *)node.schema->name);
3610 free(node.schema);
3611 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003612 lydict_remove(ctx, dflt);
Michal Vasko1dca6882015-10-22 14:29:42 +02003613
3614 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003615}
3616
Michal Vasko730dfdf2015-08-11 14:48:05 +02003617/**
3618 * @brief Check a key for mandatory attributes. Logs directly.
3619 *
3620 * @param[in] key The key to check.
3621 * @param[in] flags What flags to check.
3622 * @param[in] list The list of all the keys.
3623 * @param[in] index Index of the key in the key list.
3624 * @param[in] name The name of the keys.
3625 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003626 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003627 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003628 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003629static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003630check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003631{
Radek Krejciadb57612016-02-16 13:34:34 +01003632 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003633 char *dup = NULL;
3634 int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01003635 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003636
3637 /* existence */
3638 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003639 if (name[len] != '\0') {
3640 dup = strdup(name);
Michal Vasko53b7da02018-02-13 15:28:42 +01003641 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003642 dup[len] = '\0';
3643 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003644 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003645 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003646 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003647 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003648 }
3649
3650 /* uniqueness */
3651 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003652 if (key == list->keys[j]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003653 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003655 }
3656 }
3657
3658 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003659 if (key->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003660 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003661 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003662 }
3663
3664 /* type of the leaf is not built-in empty */
Radek Krejci13fde922018-05-16 10:45:58 +02003665 if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003666 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003667 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003668 }
3669
3670 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003671 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003672 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003673 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003674 }
3675
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003676 /* key is not placed from augment */
3677 if (key->parent->nodetype == LYS_AUGMENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003678 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3679 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003680 return -1;
3681 }
3682
Radek Krejci3f21ada2016-08-01 13:34:31 +02003683 /* key is not when/if-feature -conditional */
3684 j = 0;
3685 if (key->when || (key->iffeature_size && (j = 1))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003686 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3687 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003688 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003689 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003690 }
3691
Michal Vasko0b85aa82016-03-07 14:37:43 +01003692 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003693}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003694
3695/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003696 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003697 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003698 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003699 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003700 *
3701 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3702 */
3703int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003704resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003705{
Radek Krejci581ce772015-11-10 17:22:40 +01003706 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003707 const struct lys_node *leaf = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01003708 struct ly_ctx *ctx = parent->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003709
Michal Vaskodc300b02017-04-07 14:09:20 +02003710 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003711 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003712 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003713 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003714 if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003715 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 +02003716 } else if (rc == -2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003717 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003718 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003719 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003720 } else {
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, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003723 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003724 }
Radek Krejci581ce772015-11-10 17:22:40 +01003725 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003727 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003728 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3729 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003730 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003731 }
3732
Radek Krejcicf509982015-12-15 09:22:44 +01003733 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003734 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3735 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003736 return -1;
3737 }
3738
Radek Krejcid09d1a52016-08-11 14:05:45 +02003739 /* check that all unique's targets are of the same config type */
3740 if (*trg_type) {
3741 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003742 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3743 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003744 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3745 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3746 return -1;
3747 }
3748 } else {
3749 /* first unique */
3750 if (leaf->flags & LYS_CONFIG_W) {
3751 *trg_type = 1;
3752 } else {
3753 *trg_type = 2;
3754 }
3755 }
3756
Radek Krejcica7efb72016-01-18 13:06:01 +01003757 /* set leaf's unique flag */
3758 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3759
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003760 return EXIT_SUCCESS;
3761
3762error:
3763
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003764 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003765}
3766
Radek Krejci0c0086a2016-03-24 15:20:28 +01003767void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003768unres_data_del(struct unres_data *unres, uint32_t i)
3769{
3770 /* there are items after the one deleted */
3771 if (i+1 < unres->count) {
3772 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003773 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003774
3775 /* deleting the last item */
3776 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003777 free(unres->node);
3778 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003779 }
3780
3781 /* if there are no items after and it is not the last one, just move the counter */
3782 --unres->count;
3783}
3784
Michal Vasko0491ab32015-08-19 14:28:29 +02003785/**
3786 * @brief Resolve (find) a data node from a specific module. Does not log.
3787 *
3788 * @param[in] mod Module to search in.
3789 * @param[in] name Name of the data node.
3790 * @param[in] nam_len Length of the name.
3791 * @param[in] start Data node to start the search from.
3792 * @param[in,out] parents Resolved nodes. If there are some parents,
3793 * they are replaced (!!) with the resolvents.
3794 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003795 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003796 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003797static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003798resolve_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 +02003799{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003800 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003801 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003802 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003803
Michal Vasko23b61ec2015-08-19 11:19:50 +02003804 if (!parents->count) {
3805 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003806 parents->node = malloc(sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003807 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003808 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003809 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003810 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003811 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003812 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003813 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003814 continue;
3815 }
3816 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003817 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003818 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003819 && node->schema->name[nam_len] == '\0') {
3820 /* matching target */
3821 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003822 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003823 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003824 flag = 1;
3825 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003826 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003827 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003828 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003829 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003830 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003831 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003832 }
3833 }
3834 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003835
3836 if (!flag) {
3837 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003838 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003839 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003840 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003841 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003842 }
3843
Michal Vasko0491ab32015-08-19 14:28:29 +02003844 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003845}
3846
Michal Vaskoe27516a2016-10-10 17:55:31 +00003847static int
Michal Vasko1c007172017-03-10 10:20:44 +01003848resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003849{
3850 int dep1, dep2;
3851 const struct lys_node *node;
3852
3853 if (lys_parent(op_node)) {
3854 /* inner operation (notif/action) */
3855 if (abs_path) {
3856 return 1;
3857 } else {
3858 /* compare depth of both nodes */
3859 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3860 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3861 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3862 return 1;
3863 }
3864 }
3865 } else {
3866 /* top-level operation (notif/rpc) */
3867 if (op_node != first_node) {
3868 return 1;
3869 }
3870 }
3871
3872 return 0;
3873}
3874
Michal Vasko730dfdf2015-08-11 14:48:05 +02003875/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003876 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003877 *
Michal Vaskobb211122015-08-19 14:03:11 +02003878 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003879 * @param[in] context_node Predicate context node (where the predicate is placed).
3880 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003881 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003882 *
Michal Vasko184521f2015-09-24 13:14:26 +02003883 * @return 0 on forward reference, otherwise the number
3884 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003885 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003886 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003887static int
Michal Vasko1c007172017-03-10 10:20:44 +01003888resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3889 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003890{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003891 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003892 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003893 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003894 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3895 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003896 struct ly_ctx *ctx = context_node->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003897
3898 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003899 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003900 &pke_len, &has_predicate)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003901 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003902 return -parsed+i;
3903 }
3904 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003905 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003906
Michal Vasko58090902015-08-13 14:04:15 +02003907 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003908 if (sour_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003909 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003910 } else {
3911 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003912 }
Michal Vaskobb520442017-05-23 10:55:18 +02003913 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003914 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003915 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003916 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003917 }
3918
3919 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003920 dest_parent_times = 0;
3921 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003922 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3923 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003924 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003925 return -parsed;
3926 }
3927 pke_parsed += i;
3928
Radek Krejciadb57612016-02-16 13:34:34 +01003929 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003930 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3931 && !((struct lys_node_augment *)dst_node->parent)->target) {
3932 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003933 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003934 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3935 return 0;
3936 }
3937
Michal Vaskofbaead72016-10-07 10:54:48 +02003938 /* path is supposed to be evaluated in data tree, so we have to skip
3939 * all schema nodes that cannot be instantiated in data tree */
3940 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003941 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003942 dst_node = lys_parent(dst_node));
3943
Michal Vasko1f76a282015-08-04 16:16:53 +02003944 if (!dst_node) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003945 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003946 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003947 }
3948 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003949 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003950 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003951 if (dest_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003952 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003953 } else {
3954 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003955 }
Michal Vaskobb520442017-05-23 10:55:18 +02003956 rc = lys_getnext_data(trg_mod, dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003957 if (rc) {
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
Michal Vaskoe27516a2016-10-10 17:55:31 +00003962 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003963 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003964 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003965 }
3966 first_iter = 0;
3967 }
3968
Michal Vasko1f76a282015-08-04 16:16:53 +02003969 if (pke_len == pke_parsed) {
3970 break;
3971 }
3972
Michal Vaskobb520442017-05-23 10:55:18 +02003973 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 +02003974 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003975 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003976 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003977 return -parsed;
3978 }
3979 pke_parsed += i;
3980 }
3981
3982 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003983 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003984 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
Michal Vasko53b7da02018-02-13 15:28:42 +01003985 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003986 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003987 return -parsed;
3988 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003989 } while (has_predicate);
3990
3991 return parsed;
3992}
3993
Michal Vasko730dfdf2015-08-11 14:48:05 +02003994/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003995 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003996 *
Michal Vaskobb211122015-08-19 14:03:11 +02003997 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003998 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003999 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004000 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004001 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004002 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004003static int
Michal Vasko1c007172017-03-10 10:20:44 +01004004resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02004005{
Michal Vaskocb45f472018-02-12 10:47:42 +01004006 const struct lys_node *node, *op_node = NULL, *tmp_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02004007 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004008 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02004009 const char *id, *prefix, *name;
4010 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskocb45f472018-02-12 10:47:42 +01004011 int i, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01004012 struct ly_ctx *ctx = parent->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02004013
Michal Vasko184521f2015-09-24 13:14:26 +02004014 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004015 parent_times = 0;
4016 id = path;
4017
Michal Vasko1c007172017-03-10 10:20:44 +01004018 /* find operation schema we are in */
4019 for (op_node = lys_parent(parent);
4020 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
4021 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02004022
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004023 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02004024 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004025 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004026 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004027 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004028 }
4029 id += i;
4030
Michal Vaskobb520442017-05-23 10:55:18 +02004031 /* get the current module */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004032 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004033 if (!tmp_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004034 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vaskobb520442017-05-23 10:55:18 +02004035 return EXIT_FAILURE;
4036 }
4037 last_aug = NULL;
4038
Michal Vasko184521f2015-09-24 13:14:26 +02004039 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02004040 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02004041 /* use module data */
4042 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01004043
Michal Vasko1f76a282015-08-04 16:16:53 +02004044 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02004045 /* we are looking for the right parent */
4046 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02004047 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
4048 && !((struct lys_node_augment *)node->parent)->target) {
4049 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01004050 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02004051 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
4052 return EXIT_FAILURE;
4053 }
4054
Radek Krejci3a5501d2016-07-18 22:03:34 +02004055 /* path is supposed to be evaluated in data tree, so we have to skip
4056 * all schema nodes that cannot be instantiated in data tree */
4057 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00004058 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02004059 node = lys_parent(node));
4060
Michal Vasko1f76a282015-08-04 16:16:53 +02004061 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02004062 if (i == parent_times - 1) {
4063 /* top-level */
4064 break;
4065 }
4066
4067 /* higher than top-level */
Michal Vasko53b7da02018-02-13 15:28:42 +01004068 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004069 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02004070 }
4071 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02004072 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004073 LOGINT(ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004074 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004075 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004076 }
4077
Michal Vaskobb520442017-05-23 10:55:18 +02004078 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
4079 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004080 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02004081get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004082 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02004083 }
4084
Michal Vaskocb45f472018-02-12 10:47:42 +01004085 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
4086 node = NULL;
4087 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
4088 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
4089 continue;
4090 }
4091 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
4092 continue;
4093 }
4094 /* match */
4095 break;
4096 }
4097 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02004098 if (last_aug) {
Michal Vaskob6906872018-03-12 11:35:09 +01004099 /* restore the correct augment target */
4100 node = last_aug->target;
Michal Vaskobb520442017-05-23 10:55:18 +02004101 goto get_next_augment;
4102 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004103 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02004104 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02004105 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004106
Michal Vaskoe27516a2016-10-10 17:55:31 +00004107 if (first_iter) {
4108 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01004109 if (op_node && parent_times &&
4110 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004111 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00004112 }
4113 first_iter = 0;
4114 }
4115
Michal Vasko1f76a282015-08-04 16:16:53 +02004116 if (has_predicate) {
4117 /* we have predicate, so the current result must be list */
4118 if (node->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004119 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004120 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004121 }
4122
Michal Vasko1c007172017-03-10 10:20:44 +01004123 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02004124 if (!i) {
4125 return EXIT_FAILURE;
4126 } else if (i < 0) {
4127 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004128 }
4129 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004130 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004131 }
4132 } while (id[0]);
4133
Michal Vaskoca917682016-07-25 11:00:37 +02004134 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004135 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004136 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
4137 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004138 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004139 }
4140
Radek Krejcicf509982015-12-15 09:22:44 +01004141 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004142 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004143 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004144 return -1;
4145 }
4146
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004147 if (ret) {
4148 *ret = node;
4149 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004150
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004151 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004152}
4153
Michal Vasko730dfdf2015-08-11 14:48:05 +02004154/**
Michal Vasko718ecdd2017-10-03 14:12:39 +02004155 * @brief Compare 2 data node values.
4156 *
4157 * Comparison performed on canonical forms, the first value
4158 * is first transformed into canonical form.
4159 *
4160 * @param[in] node Leaf/leaf-list with these values.
4161 * @param[in] noncan_val Non-canonical value.
4162 * @param[in] noncan_val_len Length of \p noncal_val.
4163 * @param[in] can_val Canonical value.
4164 * @return 1 if equal, 0 if not, -1 on error (logged).
4165 */
4166static int
4167valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4168{
4169 int ret;
4170 struct lyd_node_leaf_list leaf;
4171 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4172
4173 /* dummy leaf */
4174 memset(&leaf, 0, sizeof leaf);
4175 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4176
4177repeat:
4178 leaf.value_type = sleaf->type.base;
4179 leaf.schema = node;
4180
4181 if (leaf.value_type == LY_TYPE_LEAFREF) {
4182 if (!sleaf->type.info.lref.target) {
4183 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01004184 LOGINT(node->module->ctx);
Michal Vasko718ecdd2017-10-03 14:12:39 +02004185 ret = -1;
4186 goto finish;
4187 }
4188 sleaf = sleaf->type.info.lref.target;
4189 goto repeat;
4190 } else {
Michal Vasko31a2d322018-01-12 13:36:12 +01004191 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0)) {
Michal Vasko718ecdd2017-10-03 14:12:39 +02004192 ret = -1;
4193 goto finish;
4194 }
4195 }
4196
4197 if (!strcmp(leaf.value_str, can_val)) {
4198 ret = 1;
4199 } else {
4200 ret = 0;
4201 }
4202
4203finish:
4204 lydict_remove(node->module->ctx, leaf.value_str);
4205 return ret;
4206}
4207
4208/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004209 * @brief Resolve instance-identifier predicate in JSON data format.
4210 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004211 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02004212 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02004213 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004214 * @param[in,out] node Node matching the restriction without
4215 * the predicate. If it does not satisfy the predicate,
4216 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004217 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004218 * @return Number of characters successfully parsed,
4219 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004220 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004222resolve_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 +02004223{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004224 /* ... /node[key=value] ... */
4225 struct lyd_node_leaf_list *key;
4226 struct lys_node_leaf **list_keys = NULL;
Michal Vaskoab8adcd2017-10-02 13:32:24 +02004227 struct lys_node_list *slist = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004228 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004229 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vasko53b7da02018-02-13 15:28:42 +01004230 struct ly_ctx *ctx = prev_mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004231
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004232 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02004233
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004234 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004235 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004236 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4237 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004238 }
4239 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004240
Michal Vasko88850b72017-10-02 13:13:21 +02004241 if (!(*node)) {
4242 /* just parse it all */
4243 continue;
4244 }
4245
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004246 /* target */
4247 if (name[0] == '.') {
4248 /* leaf-list value */
4249 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004250 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004251 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4252 parsed = -1;
4253 goto cleanup;
4254 }
4255
4256 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004257 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004258 *node = NULL;
4259 goto cleanup;
4260 }
4261
4262 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004263 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004264
4265 /* keyless list position */
4266 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004267 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004268 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4269 parsed = -1;
4270 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004271 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004272
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004273 if (((struct lys_node_list *)(*node)->schema)->keys) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004274 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 +02004275 (*node)->schema->name);
4276 parsed = -1;
4277 goto cleanup;
4278 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004279
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004280 /* check the index */
4281 if (atoi(name) != cur_idx) {
4282 *node = NULL;
4283 goto cleanup;
4284 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004285
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004286 } else {
4287 /* list key value */
4288 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004289 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004290 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4291 parsed = -1;
4292 goto cleanup;
4293 }
4294 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004295
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004296 /* prepare key array */
4297 if (!list_keys) {
4298 list_keys = malloc(slist->keys_size * sizeof *list_keys);
Michal Vasko53b7da02018-02-13 15:28:42 +01004299 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004300 for (i = 0; i < slist->keys_size; ++i) {
4301 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02004302 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004303 }
4304
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004305 /* find the schema key leaf */
4306 for (i = 0; i < slist->keys_size; ++i) {
4307 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4308 break;
4309 }
4310 }
4311 if (i == slist->keys_size) {
4312 /* this list has no such key */
Michal Vasko53b7da02018-02-13 15:28:42 +01004313 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004314 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4315 parsed = -1;
4316 goto cleanup;
4317 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004318
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004319 /* check module */
4320 if (model) {
4321 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004322 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 +02004323 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4324 parsed = -1;
4325 goto cleanup;
4326 }
4327 } else {
4328 if (list_keys[i]->module != prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004329 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 +02004330 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4331 parsed = -1;
4332 goto cleanup;
4333 }
4334 }
4335
4336 /* find the actual data key */
4337 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4338 if (key->schema == (struct lys_node *)list_keys[i]) {
4339 break;
4340 }
4341 }
4342 if (!key) {
4343 /* list instance is missing a key? definitely should not happen */
Michal Vasko53b7da02018-02-13 15:28:42 +01004344 LOGINT(ctx);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004345 parsed = -1;
4346 goto cleanup;
4347 }
4348
4349 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004350 if (!valequal(key->schema, value, val_len, key->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004351 *node = NULL;
Michal Vasko88850b72017-10-02 13:13:21 +02004352 /* we still want to parse the whole predicate */
4353 continue;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004354 }
4355
4356 /* everything is fine, mark this key as resolved */
4357 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004358 }
4359 } while (has_predicate);
4360
Michal Vaskob2f40be2016-09-08 16:03:48 +02004361 /* check that all list keys were specified */
Michal Vasko88850b72017-10-02 13:13:21 +02004362 if (*node && list_keys) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004363 for (i = 0; i < slist->keys_size; ++i) {
4364 if (list_keys[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004365 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 +02004366 parsed = -1;
4367 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004368 }
4369 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004370 }
4371
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004372cleanup:
4373 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004374 return parsed;
4375}
4376
Michal Vasko895c11f2018-03-12 11:35:58 +01004377static int
4378check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004379{
Michal Vasko0b963112017-08-11 12:45:36 +02004380 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004381 struct lyxp_set set;
Michal Vasko895c11f2018-03-12 11:35:58 +01004382 enum int_log_opts prev_ilo;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004383
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004384 if (check_place) {
4385 parent = node;
4386 while (parent) {
4387 if (parent->nodetype == LYS_GROUPING) {
4388 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004389 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004390 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004391 if (parent->nodetype == LYS_AUGMENT) {
4392 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004393 /* unresolved augment, skip for now (will be checked later) */
4394 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004395 } else {
4396 parent = ((struct lys_node_augment *)parent)->target;
4397 continue;
4398 }
4399 }
4400 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004401 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004402 }
4403
Michal Vasko895c11f2018-03-12 11:35:58 +01004404 memset(&set, 0, sizeof set);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004405
Michal Vasko895c11f2018-03-12 11:35:58 +01004406 /* produce just warnings */
4407 ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4408 lyxp_node_atomize(node, &set, 1);
4409 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4410
4411 if (set.val.snodes) {
4412 free(set.val.snodes);
4413 }
4414 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004415}
4416
Radek Krejcif71f48f2016-10-25 16:37:24 +02004417static int
4418check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4419{
Radek Krejcidce5f972017-09-12 15:47:49 +02004420 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004421
4422 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004423 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4424 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004425 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 +02004426 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4427 return -1;
4428 }
4429 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4430 * of leafref resolving (lys_leaf_add_leafref_target()) */
4431 } else if (type->base == LY_TYPE_UNION) {
4432 for (i = 0; i < type->info.uni.count; i++) {
4433 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4434 return -1;
4435 }
4436 }
4437 }
4438 return 0;
4439}
4440
Michal Vasko9e635ac2016-10-17 11:44:09 +02004441/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004442 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004443 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004444 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004445 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004446 * @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 +02004447 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004448 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004449 *
4450 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004451 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004452int
4453inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004454{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004455 struct lys_node_leaf *leaf;
Michal Vasko53b7da02018-02-13 15:28:42 +01004456 struct ly_ctx *ctx;
4457
4458 if (!node) {
4459 return 0;
4460 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004461
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004462 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Michal Vasko53b7da02018-02-13 15:28:42 +01004463 ctx = node->module->ctx;
4464
Radek Krejci1d82ef62015-08-07 14:44:40 +02004465 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004466 if (clear) {
4467 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004468 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004469 } else {
4470 if (node->flags & LYS_CONFIG_SET) {
4471 /* skip nodes with an explicit config value */
4472 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004473 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4474 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004475 return -1;
4476 }
4477 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004478 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004479
4480 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4481 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4482 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004483 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4484 && !((struct lys_node_list *)node)->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004485 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
Michal Vaskoe022a562016-09-27 14:24:15 +02004486 return -1;
4487 }
4488 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004489 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004490 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004491 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004492 return -1;
4493 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004494 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4495 leaf = (struct lys_node_leaf *)node;
4496 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004497 return -1;
4498 }
4499 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004500 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004501
4502 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004503}
4504
Michal Vasko730dfdf2015-08-11 14:48:05 +02004505/**
Michal Vasko7178e692016-02-12 15:58:05 +01004506 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004507 *
Michal Vaskobb211122015-08-19 14:03:11 +02004508 * @param[in] aug Augment to use.
Michal Vasko97234262018-02-01 09:53:01 +01004509 * @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 +01004510 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004511 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004512 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004513 */
Michal Vasko7178e692016-02-12 15:58:05 +01004514static int
Michal Vasko97234262018-02-01 09:53:01 +01004515resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004516{
Michal Vasko44ab1462017-05-18 13:18:36 +02004517 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004518 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004519 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004520 struct ly_set *set;
Michal Vasko53b7da02018-02-13 15:28:42 +01004521 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004522
Michal Vasko2ef7db62017-06-12 09:24:02 +02004523 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004524 mod = lys_main_module(aug->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01004525 ctx = mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004526
Michal Vaskobb520442017-05-23 10:55:18 +02004527 /* set it as not applied for now */
4528 aug->flags |= LYS_NOTAPPLIED;
4529
Michal Vasko2ef7db62017-06-12 09:24:02 +02004530 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004531 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004532 /* resolve target node */
Michal Vasko97234262018-02-01 09:53:01 +01004533 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 +02004534 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004535 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004536 return -1;
4537 }
Michal Vasko50576712017-07-28 12:28:33 +02004538 if (!set) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004539 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004540 return EXIT_FAILURE;
4541 }
Michal Vasko50576712017-07-28 12:28:33 +02004542 aug->target = set->set.s[0];
4543 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004544 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004545
Michal Vaskod58d5962016-03-02 14:29:41 +01004546 /* check for mandatory nodes - if the target node is in another module
4547 * the added nodes cannot be mandatory
4548 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004549 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4550 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004551 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004552 }
4553
Michal Vasko07e89ef2016-03-03 13:28:57 +01004554 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004555 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004556 LY_TREE_FOR(aug->child, sub) {
4557 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4558 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004559 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4560 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004561 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004562 return -1;
4563 }
4564 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004565 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004566 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004567 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004568 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4569 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004570 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004571 return -1;
4572 }
4573 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004574 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004575 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004576 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004577 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4578 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004579 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004580 return -1;
4581 }
4582 }
4583 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004584 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4585 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 +01004586 return -1;
4587 }
4588
Radek Krejcic071c542016-01-27 14:57:51 +01004589 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004590 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004591 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004592 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004593 }
4594 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004595
Michal Vasko44ab1462017-05-18 13:18:36 +02004596 if (!aug->child) {
4597 /* empty augment, nothing to connect, but it is techincally applied */
Michal Vasko53b7da02018-02-13 15:28:42 +01004598 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
Michal Vasko44ab1462017-05-18 13:18:36 +02004599 aug->flags &= ~LYS_NOTAPPLIED;
Radek Krejciaa6b2a12017-10-26 15:52:39 +02004600 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4601 /* we try to connect the augment only in case the module is implemented or
4602 * the augment applies on the used grouping, anyway we failed here */
Michal Vasko44ab1462017-05-18 13:18:36 +02004603 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004604 }
4605
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004606 return EXIT_SUCCESS;
4607}
4608
Radek Krejcie534c132016-11-23 13:32:31 +01004609static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004610resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004611{
4612 enum LY_VLOG_ELEM vlog_type;
4613 void *vlog_node;
4614 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004615 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004616 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004617 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004618 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004619 struct lys_ext_instance *tmp_ext;
Michal Vasko53b7da02018-02-13 15:28:42 +01004620 struct ly_ctx *ctx = NULL;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004621 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004622
4623 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004624 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004625 vlog_node = info->parent;
4626 vlog_type = LY_VLOG_LYS;
4627 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004628 case LYEXT_PAR_MODULE:
4629 case LYEXT_PAR_IMPORT:
4630 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004631 vlog_node = NULL;
4632 vlog_type = LY_VLOG_LYS;
4633 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004634 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004635 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004636 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004637 break;
4638 }
4639
4640 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004641 /* YIN */
4642
Radek Krejcie534c132016-11-23 13:32:31 +01004643 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004644 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004645 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004646 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004647 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004648 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004649 ctx = mod->ctx;
Radek Krejcie534c132016-11-23 13:32:31 +01004650
4651 /* find the extension definition */
4652 e = NULL;
4653 for (i = 0; i < mod->extensions_size; i++) {
4654 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4655 e = &mod->extensions[i];
4656 break;
4657 }
4658 }
4659 /* try submodules */
4660 for (j = 0; !e && j < mod->inc_size; j++) {
4661 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4662 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4663 e = &mod->inc[j].submodule->extensions[i];
4664 break;
4665 }
4666 }
4667 }
4668 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004669 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004670 return EXIT_FAILURE;
4671 }
4672
4673 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004674
Radek Krejci72b35992017-01-04 16:27:44 +01004675 if (e->plugin && e->plugin->check_position) {
4676 /* common part - we have plugin with position checking function, use it first */
4677 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4678 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004679 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004680 return -1;
4681 }
4682 }
4683
Radek Krejci8d6b7422017-02-03 14:42:13 +01004684 /* extension type-specific part - allocation */
4685 if (e->plugin) {
4686 etype = e->plugin->type;
4687 } else {
4688 /* default type */
4689 etype = LYEXT_FLAG;
4690 }
4691 switch (etype) {
4692 case LYEXT_FLAG:
4693 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4694 break;
4695 case LYEXT_COMPLEX:
4696 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4697 break;
4698 case LYEXT_ERR:
4699 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004700 LOGINT(ctx);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004701 return -1;
4702 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004703 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004704
4705 /* common part for all extension types */
4706 (*ext)->def = e;
4707 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004708 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004709 (*ext)->insubstmt = info->substmt;
4710 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004711 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004712 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004713
PavolVicand86b0d62017-09-01 11:01:39 +02004714 if (e->argument) {
4715 if (!(e->flags & LYS_YINELEM)) {
4716 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4717 if (!(*ext)->arg_value) {
PavolVicane7a1fc62018-02-19 16:50:27 +01004718 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
PavolVicand86b0d62017-09-01 11:01:39 +02004719 return -1;
4720 }
4721
4722 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4723 } else {
4724 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4725 if (ly_strequal(yin->name, e->argument, 1)) {
4726 (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
4727 lyxml_free(mod->ctx, yin);
4728 break;
4729 }
4730 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004731 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004732 }
4733
PavolVican92f23622017-12-12 13:35:56 +01004734 if ((*ext)->flags & LYEXT_OPT_VALID &&
4735 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004736 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004737 }
4738
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004739 (*ext)->nodetype = LYS_EXT;
4740 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004741
Radek Krejci8d6b7422017-02-03 14:42:13 +01004742 /* extension type-specific part - parsing content */
4743 switch (etype) {
4744 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004745 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4746 if (!yin->ns) {
4747 /* garbage */
4748 lyxml_free(mod->ctx, yin);
4749 continue;
4750 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4751 /* standard YANG statements are not expected here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004752 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004753 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004754 } else if (yin->ns == info->data.yin->ns &&
4755 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004756 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004757 if ((*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004758 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004759 return -1;
4760 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004761 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004762 yin->content = NULL;
4763 lyxml_free(mod->ctx, yin);
4764 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004765 /* extension instance */
4766 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4767 LYEXT_SUBSTMT_SELF, 0, unres)) {
4768 return -1;
4769 }
Radek Krejci72b35992017-01-04 16:27:44 +01004770
Radek Krejci72b35992017-01-04 16:27:44 +01004771 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004772 }
Radek Krejci72b35992017-01-04 16:27:44 +01004773 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004774 break;
4775 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004776 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004777 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4778 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004779 return -1;
4780 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004781 break;
4782 default:
4783 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004784 }
Radek Krejci72b35992017-01-04 16:27:44 +01004785
4786 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4787
Radek Krejcie534c132016-11-23 13:32:31 +01004788 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004789 /* YANG */
4790
PavolVicanc1807262017-01-31 18:00:27 +01004791 ext_prefix = (char *)(*ext)->def;
4792 tmp = strchr(ext_prefix, ':');
4793 if (!tmp) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004794 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004795 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004796 }
4797 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004798
PavolVicanc1807262017-01-31 18:00:27 +01004799 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004800 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
PavolVicanc1807262017-01-31 18:00:27 +01004801 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004802 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004803 return EXIT_FAILURE;
4804 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004805 ctx = mod->ctx;
PavolVicanc1807262017-01-31 18:00:27 +01004806
4807 /* find the extension definition */
4808 e = NULL;
4809 for (i = 0; i < mod->extensions_size; i++) {
4810 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4811 e = &mod->extensions[i];
4812 break;
4813 }
4814 }
4815 /* try submodules */
4816 for (j = 0; !e && j < mod->inc_size; j++) {
4817 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4818 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4819 e = &mod->inc[j].submodule->extensions[i];
4820 break;
4821 }
4822 }
4823 }
4824 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004825 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004826 return EXIT_FAILURE;
4827 }
4828
PavolVicanfcc98762017-09-01 15:51:39 +02004829 (*ext)->flags &= ~LYEXT_OPT_YANG;
4830 (*ext)->def = NULL;
4831
PavolVicanc1807262017-01-31 18:00:27 +01004832 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4833
4834 if (e->plugin && e->plugin->check_position) {
4835 /* common part - we have plugin with position checking function, use it first */
4836 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4837 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004838 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004839 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004840 }
4841 }
4842
PavolVican22e88682017-02-14 22:38:18 +01004843 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004844 (*ext)->def = e;
4845 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004846 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004847 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
PavolVican22e88682017-02-14 22:38:18 +01004848
PavolVicanb0d84102017-02-15 16:32:42 +01004849 if (e->argument && !(*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004850 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
PavolVicanb0d84102017-02-15 16:32:42 +01004851 goto error;
4852 }
4853
PavolVican92f23622017-12-12 13:35:56 +01004854 if ((*ext)->flags & LYEXT_OPT_VALID &&
4855 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004856 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
PavolVican92f23622017-12-12 13:35:56 +01004857 }
4858
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004859 (*ext)->module = info->mod;
4860 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004861
PavolVican22e88682017-02-14 22:38:18 +01004862 /* extension type-specific part */
4863 if (e->plugin) {
4864 etype = e->plugin->type;
4865 } else {
4866 /* default type */
4867 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004868 }
PavolVican22e88682017-02-14 22:38:18 +01004869 switch (etype) {
4870 case LYEXT_FLAG:
4871 /* nothing change */
4872 break;
4873 case LYEXT_COMPLEX:
4874 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Michal Vasko53b7da02018-02-13 15:28:42 +01004875 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
PavolVican22e88682017-02-14 22:38:18 +01004876 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4877 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004878 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004879 if (info->data.yang) {
4880 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004881 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4882 (struct lys_ext_instance_complex*)(*ext))) {
4883 goto error;
4884 }
4885 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4886 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004887 goto error;
4888 }
PavolVicana3876672017-02-21 15:49:51 +01004889 }
4890 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4891 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004892 }
PavolVican22e88682017-02-14 22:38:18 +01004893 break;
4894 case LYEXT_ERR:
4895 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004896 LOGINT(ctx);
PavolVican22e88682017-02-14 22:38:18 +01004897 goto error;
4898 }
4899
PavolVican22e88682017-02-14 22:38:18 +01004900 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4901 goto error;
4902 }
4903 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004904 }
4905
4906 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004907error:
4908 free(ext_prefix);
4909 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004910}
4911
Michal Vasko730dfdf2015-08-11 14:48:05 +02004912/**
Pavol Vican855ca622016-09-05 13:07:54 +02004913 * @brief Resolve (find) choice default case. Does not log.
4914 *
4915 * @param[in] choic Choice to use.
4916 * @param[in] dflt Name of the default case.
4917 *
4918 * @return Pointer to the default node or NULL.
4919 */
4920static struct lys_node *
4921resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4922{
4923 struct lys_node *child, *ret;
4924
4925 LY_TREE_FOR(choic->child, child) {
4926 if (child->nodetype == LYS_USES) {
4927 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4928 if (ret) {
4929 return ret;
4930 }
4931 }
4932
4933 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004934 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004935 return child;
4936 }
4937 }
4938
4939 return NULL;
4940}
4941
4942/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004943 * @brief Resolve uses, apply augments, refines. Logs directly.
4944 *
Michal Vaskobb211122015-08-19 14:03:11 +02004945 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004946 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004947 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004948 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004949 */
Michal Vasko184521f2015-09-24 13:14:26 +02004950static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004951resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004952{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004953 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004954 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004955 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004956 struct lys_node_leaflist *llist;
4957 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004958 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004959 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004960 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004961 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004962 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004963 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004964
Michal Vasko71e1aa82015-08-12 12:17:51 +02004965 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004966
Radek Krejci93def382017-05-24 15:33:48 +02004967 /* check that the grouping is resolved (no unresolved uses inside) */
4968 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004969
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004970 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004971 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004972 if (node_aux->nodetype & LYS_GROUPING) {
4973 /* do not instantiate groupings from groupings */
4974 continue;
4975 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004976 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004977 if (!node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004978 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4979 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004980 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004981 }
Pavol Vican55abd332016-07-12 15:54:49 +02004982 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004983 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 +02004984 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004985 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004986 }
4987 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004988 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004989
Michal Vaskodef0db12015-10-07 13:22:48 +02004990 /* we managed to copy the grouping, the rest must be possible to resolve */
4991
Pavol Vican855ca622016-09-05 13:07:54 +02004992 if (uses->refine_size) {
4993 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Michal Vasko53b7da02018-02-13 15:28:42 +01004994 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004995 }
4996
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004997 /* apply refines */
4998 for (i = 0; i < uses->refine_size; i++) {
4999 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01005000 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
5001 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02005002 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01005003 if (rc || !node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005004 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005005 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005006 }
5007
Radek Krejci1d82ef62015-08-07 14:44:40 +02005008 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005009 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5010 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005011 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005012 }
Pavol Vican855ca622016-09-05 13:07:54 +02005013 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005014
5015 /* description on any nodetype */
5016 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005017 lydict_remove(ctx, node->dsc);
5018 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005019 }
5020
5021 /* reference on any nodetype */
5022 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005023 lydict_remove(ctx, node->ref);
5024 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005025 }
5026
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005027 /* config on any nodetype,
5028 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
5029 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005030 node->flags &= ~LYS_CONFIG_MASK;
5031 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005032 }
5033
5034 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02005035 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005036 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005037 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02005038 leaf = (struct lys_node_leaf *)node;
5039
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005040 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02005041 lydict_remove(ctx, leaf->dflt);
5042 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
5043
5044 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01005045 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
5046 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005047 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005048 }
Radek Krejci200bf712016-08-16 17:11:04 +02005049 } else if (node->nodetype == LYS_LEAFLIST) {
5050 /* leaf-list */
5051 llist = (struct lys_node_leaflist *)node;
5052
5053 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01005054 for (j = 0; j < llist->dflt_size; j++) {
5055 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02005056 }
5057 free(llist->dflt);
5058
5059 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02005060 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
Michal Vasko53b7da02018-02-13 15:28:42 +01005061 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
Radek Krejci200bf712016-08-16 17:11:04 +02005062 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01005063 for (j = 0; j < llist->dflt_size; j++) {
5064 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02005065 }
5066
5067 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01005068 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01005069 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01005070 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02005071 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02005072 }
5073 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005074 }
5075 }
5076
5077 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02005078 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01005079 /* remove current value */
5080 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005081
Radek Krejcibf285832017-01-26 16:05:41 +01005082 /* set new value */
5083 node->flags |= (rfn->flags & LYS_MAND_MASK);
5084
Pavol Vican855ca622016-09-05 13:07:54 +02005085 if (rfn->flags & LYS_MAND_TRUE) {
5086 /* check if node has default value */
5087 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005088 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005089 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005090 goto fail;
5091 }
5092 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005093 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005094 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005095 goto fail;
5096 }
5097 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005098 }
5099
5100 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005101 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
5102 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
5103 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005104 }
5105
5106 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005107 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005108 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005109 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005110 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005111 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005112 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005113 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02005114 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005115 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005116 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005117 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005118 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005119 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005120 }
5121 }
5122
5123 /* must in leaf, leaf-list, list, container or anyxml */
5124 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005125 switch (node->nodetype) {
5126 case LYS_LEAF:
5127 old_size = &((struct lys_node_leaf *)node)->must_size;
5128 old_must = &((struct lys_node_leaf *)node)->must;
5129 break;
5130 case LYS_LEAFLIST:
5131 old_size = &((struct lys_node_leaflist *)node)->must_size;
5132 old_must = &((struct lys_node_leaflist *)node)->must;
5133 break;
5134 case LYS_LIST:
5135 old_size = &((struct lys_node_list *)node)->must_size;
5136 old_must = &((struct lys_node_list *)node)->must;
5137 break;
5138 case LYS_CONTAINER:
5139 old_size = &((struct lys_node_container *)node)->must_size;
5140 old_must = &((struct lys_node_container *)node)->must;
5141 break;
5142 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005143 case LYS_ANYDATA:
5144 old_size = &((struct lys_node_anydata *)node)->must_size;
5145 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005146 break;
5147 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01005148 LOGINT(ctx);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005149 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005150 }
5151
5152 size = *old_size + rfn->must_size;
5153 must = realloc(*old_must, size * sizeof *rfn->must);
Michal Vasko53b7da02018-02-13 15:28:42 +01005154 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005155 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01005156 must[j].ext_size = rfn->must[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005157 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 +02005158 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02005159 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5160 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5161 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5162 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5163 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02005164 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005165 }
5166
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005167 *old_must = must;
5168 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02005169
5170 /* check XPath dependencies again */
5171 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5172 goto fail;
5173 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005174 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02005175
5176 /* if-feature in leaf, leaf-list, list, container or anyxml */
5177 if (rfn->iffeature_size) {
5178 old_size = &node->iffeature_size;
5179 old_iff = &node->iffeature;
5180
5181 size = *old_size + rfn->iffeature_size;
5182 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Michal Vasko53b7da02018-02-13 15:28:42 +01005183 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02005184 *old_iff = iff;
5185
Pavol Vican855ca622016-09-05 13:07:54 +02005186 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5187 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005188 if (usize1) {
5189 /* there is something to duplicate */
5190 /* duplicate compiled expression */
5191 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
5192 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Michal Vasko53b7da02018-02-13 15:28:42 +01005193 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005194 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005195
5196 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005197 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Michal Vasko53b7da02018-02-13 15:28:42 +01005198 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005199 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005200
Radek Krejci3a3b2002017-09-13 16:39:02 +02005201 /* duplicate extensions */
5202 iff[j].ext_size = rfn->iffeature[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005203 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
Radek Krejci3a3b2002017-09-13 16:39:02 +02005204 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5205 }
5206 (*old_size)++;
5207 }
5208 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005209 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005210 }
5211
5212 /* apply augments */
5213 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko97234262018-02-01 09:53:01 +01005214 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005215 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005216 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005217 }
5218 }
5219
Pavol Vican855ca622016-09-05 13:07:54 +02005220 /* check refines */
5221 for (i = 0; i < uses->refine_size; i++) {
5222 node = refine_nodes[i];
5223 rfn = &uses->refine[i];
5224
5225 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005226 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005227 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005228 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005229 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5230 (rfn->flags & LYS_CONFIG_W)) {
5231 /* setting config true under config false is prohibited */
Michal Vasko53b7da02018-02-13 15:28:42 +01005232 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5233 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005234 "changing config from 'false' to 'true' is prohibited while "
5235 "the target's parent is still config 'false'.");
5236 goto fail;
5237 }
5238
5239 /* inherit config change to the target children */
5240 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5241 if (rfn->flags & LYS_CONFIG_W) {
5242 if (iter->flags & LYS_CONFIG_SET) {
5243 /* config is set explicitely, go to next sibling */
5244 next = NULL;
5245 goto nextsibling;
5246 }
5247 } else { /* LYS_CONFIG_R */
5248 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5249 /* error - we would have config data under status data */
Michal Vasko53b7da02018-02-13 15:28:42 +01005250 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5251 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005252 "changing config from 'true' to 'false' is prohibited while the target "
5253 "has still a children with explicit config 'true'.");
5254 goto fail;
5255 }
5256 }
5257 /* change config */
5258 iter->flags &= ~LYS_CONFIG_MASK;
5259 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5260
5261 /* select next iter - modified LY_TREE_DFS_END */
5262 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5263 next = NULL;
5264 } else {
5265 next = iter->child;
5266 }
5267nextsibling:
5268 if (!next) {
5269 /* try siblings */
5270 next = iter->next;
5271 }
5272 while (!next) {
5273 /* parent is already processed, go to its sibling */
5274 iter = lys_parent(iter);
5275
5276 /* no siblings, go back through parents */
5277 if (iter == node) {
5278 /* we are done, no next element to process */
5279 break;
5280 }
5281 next = iter->next;
5282 }
5283 }
5284 }
5285
5286 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005287 if (rfn->dflt_size) {
5288 if (node->nodetype == LYS_CHOICE) {
5289 /* choice */
5290 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5291 rfn->dflt[0]);
5292 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005293 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005294 goto fail;
5295 }
5296 if (lyp_check_mandatory_choice(node)) {
5297 goto fail;
5298 }
Pavol Vican855ca622016-09-05 13:07:54 +02005299 }
5300 }
5301
5302 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005303 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005304 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005305 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5306 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005307 goto fail;
5308 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005309 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005310 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005311 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5312 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005313 goto fail;
5314 }
5315 }
5316
5317 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005318 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005319 if (node->nodetype == LYS_LEAFLIST) {
5320 llist = (struct lys_node_leaflist *)node;
5321 if (llist->dflt_size && llist->min) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005322 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5323 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005324 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5325 goto fail;
5326 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005327 } else if (node->nodetype == LYS_LEAF) {
5328 leaf = (struct lys_node_leaf *)node;
5329 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005330 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5331 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005332 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5333 goto fail;
5334 }
Pavol Vican855ca622016-09-05 13:07:54 +02005335 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005336
Pavol Vican855ca622016-09-05 13:07:54 +02005337 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005338 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005339 for (parent = node->parent;
5340 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5341 parent = parent->parent) {
5342 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5343 /* stop also on presence containers */
5344 break;
5345 }
5346 }
5347 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5348 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5349 if (lyp_check_mandatory_choice(parent)) {
5350 goto fail;
5351 }
5352 }
5353 }
5354 }
5355 free(refine_nodes);
5356
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005357 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005358
5359fail:
5360 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5361 lys_node_free(iter, NULL, 0);
5362 }
Pavol Vican855ca622016-09-05 13:07:54 +02005363 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005364 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005365}
5366
Radek Krejci83a4bac2017-02-07 15:53:04 +01005367void
5368resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005369{
5370 int i;
5371
5372 assert(der && base);
5373
Radek Krejci018f1f52016-08-03 16:01:20 +02005374 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005375 /* create a set for backlinks if it does not exist */
5376 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005377 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005378 /* store backlink */
5379 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005380
Radek Krejci85a54be2016-10-20 12:39:56 +02005381 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005382 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005383 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005384 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005385}
5386
Michal Vasko730dfdf2015-08-11 14:48:05 +02005387/**
5388 * @brief Resolve base identity recursively. Does not log.
5389 *
5390 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005391 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005392 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005393 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005394 *
Radek Krejci219fa612016-08-15 10:36:51 +02005395 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005396 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005397static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005398resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005399 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005400{
Michal Vaskof02e3742015-08-05 16:27:02 +02005401 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005402 struct lys_ident *base = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005403 struct ly_ctx *ctx = module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005404
Radek Krejcicf509982015-12-15 09:22:44 +01005405 assert(ret);
5406
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005407 /* search module */
5408 for (i = 0; i < module->ident_size; i++) {
5409 if (!strcmp(basename, module->ident[i].name)) {
5410
5411 if (!ident) {
5412 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005413 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005414 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005415 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005416 }
5417
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005418 base = &module->ident[i];
5419 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005420 }
5421 }
5422
5423 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005424 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5425 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5426 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005427
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005428 if (!ident) {
5429 *ret = &module->inc[j].submodule->ident[i];
5430 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005431 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005432
5433 base = &module->inc[j].submodule->ident[i];
5434 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005435 }
5436 }
5437 }
5438
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005439matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005440 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005441 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005442 /* is it already completely resolved? */
5443 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005444 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005445 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5446
5447 /* simple check for circular reference,
5448 * the complete check is done as a side effect of using only completely
5449 * resolved identities (previous check of unres content) */
5450 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005451 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5452 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005453 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005454 }
5455
Radek Krejci06f64ed2016-08-15 11:07:44 +02005456 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005457 }
5458 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005459
Radek Krejcibabbff82016-02-19 13:31:37 +01005460 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005461 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005462 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005463 }
5464
Radek Krejci219fa612016-08-15 10:36:51 +02005465 /* base not found (maybe a forward reference) */
5466 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005467}
5468
Michal Vasko730dfdf2015-08-11 14:48:05 +02005469/**
5470 * @brief Resolve base identity. Logs directly.
5471 *
5472 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005473 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005474 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005475 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005476 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005477 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005478 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005479 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005480static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005481resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005482 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005483{
5484 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005485 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005486 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005487 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005488 struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005489 struct ly_ctx *ctx = module->ctx;
Radek Krejcicf509982015-12-15 09:22:44 +01005490
5491 assert((ident && !type) || (!ident && type));
5492
5493 if (!type) {
5494 /* have ident to resolve */
5495 ret = &target;
5496 flags = ident->flags;
5497 mod = ident->module;
5498 } else {
5499 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005500 ++type->info.ident.count;
5501 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 +01005502 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005503
5504 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005505 flags = type->parent->flags;
5506 mod = type->parent->module;
5507 }
Michal Vaskof2006002016-04-21 16:28:15 +02005508 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005509
5510 /* search for the base identity */
5511 name = strchr(basename, ':');
5512 if (name) {
5513 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005514 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005515 name++;
5516
Michal Vasko2d851a92015-10-20 16:16:36 +02005517 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005518 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005519 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005520 }
5521 } else {
5522 name = basename;
5523 }
5524
Radek Krejcic071c542016-01-27 14:57:51 +01005525 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005526 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
Radek Krejcic071c542016-01-27 14:57:51 +01005527 if (!module) {
5528 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01005529 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005530 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005531 }
5532
Radek Krejcic071c542016-01-27 14:57:51 +01005533 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005534 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5535 if (!rc) {
5536 assert(*ret);
5537
5538 /* check status */
5539 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5540 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5541 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005542 } else if (ident) {
5543 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005544 if (lys_main_module(mod)->implemented) {
5545 /* in case of the implemented identity, maintain backlinks to it
5546 * from the base identities to make it available when resolving
5547 * data with the identity values (not implemented identity is not
5548 * allowed as an identityref value). */
5549 resolve_identity_backlink_update(ident, *ret);
5550 }
Radek Krejci219fa612016-08-15 10:36:51 +02005551 }
5552 } else if (rc == EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005553 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005554 if (type) {
5555 --type->info.ident.count;
5556 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005557 }
5558
Radek Krejci219fa612016-08-15 10:36:51 +02005559 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005560}
5561
Radek Krejci9e6af732017-04-27 14:40:25 +02005562/*
5563 * 1 - true (der is derived from base)
5564 * 0 - false (der is not derived from base)
5565 */
5566static int
5567search_base_identity(struct lys_ident *der, struct lys_ident *base)
5568{
5569 int i;
5570
5571 if (der == base) {
5572 return 1;
5573 } else {
5574 for(i = 0; i < der->base_size; i++) {
5575 if (search_base_identity(der->base[i], base) == 1) {
5576 return 1;
5577 }
5578 }
5579 }
5580
5581 return 0;
5582}
5583
Michal Vasko730dfdf2015-08-11 14:48:05 +02005584/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005585 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005586 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005587 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005588 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005589 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005590 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005591 *
5592 * @return Pointer to the identity resolvent, NULL on error.
5593 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005594struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005595resolve_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 +02005596{
Radek Krejci9e6af732017-04-27 14:40:25 +02005597 const char *mod_name, *name;
Michal Vasko08767f72017-10-06 14:38:08 +02005598 char *str;
Radek Krejcidce5f972017-09-12 15:47:49 +02005599 int mod_name_len, nam_len, rc;
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005600 int need_implemented = 0;
Michal Vasko08767f72017-10-06 14:38:08 +02005601 unsigned int i, j;
Michal Vaskof2d43962016-09-02 11:10:16 +02005602 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005603 struct lys_module *imod = NULL, *m;
Michal Vasko53b7da02018-02-13 15:28:42 +01005604 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005605
Radek Krejci9e6af732017-04-27 14:40:25 +02005606 assert(type && ident_name && node && mod);
Michal Vasko53b7da02018-02-13 15:28:42 +01005607 ctx = mod->ctx;
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005608
Michal Vaskof2d43962016-09-02 11:10:16 +02005609 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005610 return NULL;
5611 }
5612
Michal Vasko50576712017-07-28 12:28:33 +02005613 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005614 if (rc < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005615 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005616 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005617 } else if (rc < (signed)strlen(ident_name)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005618 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005619 return NULL;
5620 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005621
5622 m = lys_main_module(mod); /* shortcut */
5623 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5624 /* identity is defined in the same module as node */
5625 imod = m;
5626 } else if (dflt) {
5627 /* solving identityref in default definition in schema -
5628 * find the identity's module in the imported modules list to have a correct revision */
5629 for (i = 0; i < mod->imp_size; i++) {
5630 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5631 imod = mod->imp[i].module;
5632 break;
5633 }
5634 }
5635 } else {
Michal Vasko08767f72017-10-06 14:38:08 +02005636 /* solving identityref in data - get the module from the context */
5637 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5638 imod = mod->ctx->models.list[i];
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005639 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
Radek Krejci9e6af732017-04-27 14:40:25 +02005640 break;
5641 }
Michal Vasko08767f72017-10-06 14:38:08 +02005642 imod = NULL;
5643 }
Radek Krejci5ba05102017-10-26 15:02:52 +02005644 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5645 /* we are currently parsing some module and checking XPath or a default value,
5646 * so take this module into account */
5647 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5648 imod = mod->ctx->models.parsing_sub_modules[i];
5649 if (imod->type) {
5650 /* skip submodules */
5651 continue;
5652 }
5653 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5654 break;
5655 }
5656 imod = NULL;
5657 }
5658 }
Michal Vasko08767f72017-10-06 14:38:08 +02005659 }
5660
Michal Vasko53b7da02018-02-13 15:28:42 +01005661 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
Michal Vasko08767f72017-10-06 14:38:08 +02005662 /* the needed module was not found, but it may have been expected so call the data callback */
5663 if (imod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005664 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci58523dc2017-10-27 10:00:17 +02005665 } else if (mod_name) {
Michal Vasko08767f72017-10-06 14:38:08 +02005666 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01005667 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
Michal Vasko08767f72017-10-06 14:38:08 +02005668 free(str);
Radek Krejci9e6af732017-04-27 14:40:25 +02005669 }
5670 }
5671 if (!imod) {
5672 goto fail;
5673 }
5674
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005675 if (m != imod || lys_main_module(type->parent->module) != mod) {
Michal Vasko08767f72017-10-06 14:38:08 +02005676 /* the type is not referencing the same schema,
Radek Krejci9e6af732017-04-27 14:40:25 +02005677 * THEN, we may need to make the module with the identity implemented, but only if it really
5678 * contains the identity */
5679 if (!imod->implemented) {
5680 cur = NULL;
5681 /* get the identity in the module */
5682 for (i = 0; i < imod->ident_size; i++) {
5683 if (!strcmp(name, imod->ident[i].name)) {
5684 cur = &imod->ident[i];
5685 break;
5686 }
5687 }
5688 if (!cur) {
5689 /* go through includes */
5690 for (j = 0; j < imod->inc_size; j++) {
5691 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5692 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5693 cur = &imod->inc[j].submodule->ident[i];
5694 break;
5695 }
5696 }
5697 }
5698 if (!cur) {
5699 goto fail;
5700 }
5701 }
5702
5703 /* check that identity is derived from one of the type's base */
5704 while (type->der) {
5705 for (i = 0; i < type->info.ident.count; i++) {
5706 if (search_base_identity(cur, type->info.ident.ref[i])) {
5707 /* cur's base matches the type's base */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005708 need_implemented = 1;
Radek Krejci9e6af732017-04-27 14:40:25 +02005709 goto match;
5710 }
5711 }
5712 type = &type->der->type;
5713 }
5714 /* matching base not found */
Michal Vasko53b7da02018-02-13 15:28:42 +01005715 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Radek Krejci9e6af732017-04-27 14:40:25 +02005716 goto fail;
5717 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005718 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005719
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005720 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005721 while (type->der) {
5722 for (i = 0; i < type->info.ident.count; ++i) {
5723 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005724
Radek Krejci85a54be2016-10-20 12:39:56 +02005725 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005726 /* there are some derived identities */
Michal Vasko08767f72017-10-06 14:38:08 +02005727 for (j = 0; j < cur->der->number; j++) {
5728 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005729 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005730 /* we have match */
5731 cur = der;
5732 goto match;
5733 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005734 }
5735 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005736 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005737 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005738 }
5739
Radek Krejci9e6af732017-04-27 14:40:25 +02005740fail:
Michal Vasko53b7da02018-02-13 15:28:42 +01005741 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005742 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005743
5744match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005745 for (i = 0; i < cur->iffeature_size; i++) {
5746 if (!resolve_iffeature(&cur->iffeature[i])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005747 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5748 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005749 return NULL;
5750 }
5751 }
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005752 if (need_implemented) {
5753 if (dflt) {
5754 /* try to make the module implemented */
5755 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5756 imod->name, cur->name, mod->name);
5757 if (lys_set_implemented(imod)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005758 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005759 imod->name, cur->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01005760 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005761 goto fail;
5762 }
5763 } else {
5764 /* just say that it was found, but in a non-implemented module */
Michal Vasko53b7da02018-02-13 15:28:42 +01005765 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005766 lys_main_module(cur->module)->name);
Radek Krejci9e6af732017-04-27 14:40:25 +02005767 goto fail;
5768 }
5769 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005770 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005771}
5772
Michal Vasko730dfdf2015-08-11 14:48:05 +02005773/**
Michal Vaskobb211122015-08-19 14:03:11 +02005774 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005775 *
Michal Vaskobb211122015-08-19 14:03:11 +02005776 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005777 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005778 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005779 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005780 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005781static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005782resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005783{
Radek Krejci93def382017-05-24 15:33:48 +02005784 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005785 struct lys_node *par_grp;
Michal Vasko53b7da02018-02-13 15:28:42 +01005786 struct ly_ctx *ctx = uses->module->ctx;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005787
Radek Krejci6ff885d2017-01-03 14:06:22 +01005788 /* 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 +02005789 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5790 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5791 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005792 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoe91afce2015-08-12 12:21:00 +02005793
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005794 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005795 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5796 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005797 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005798 return -1;
5799 } else if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005800 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005801 return -1;
5802 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005803 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005804 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005805 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005806 return -1;
5807 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005808 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005809 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005810 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005811 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005812 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005813 }
5814
Radek Krejci93def382017-05-24 15:33:48 +02005815 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005816 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005817 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005818 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005819 return -1;
5820 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005821 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005822 } else {
5823 /* instantiate grouping only when it is completely resolved */
5824 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005825 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005826 return EXIT_FAILURE;
5827 }
5828
Radek Krejci48464ed2016-03-17 15:44:09 +01005829 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005830 if (!rc) {
5831 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005832 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005833 assert(((struct lys_node_grp *)par_grp)->unres_count);
5834 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005835 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005836 }
Radek Krejcicf509982015-12-15 09:22:44 +01005837
5838 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005839 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005840 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005841 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005842 return -1;
5843 }
5844
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005845 return EXIT_SUCCESS;
5846 }
5847
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005848 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005849}
5850
Michal Vasko730dfdf2015-08-11 14:48:05 +02005851/**
Michal Vasko9957e592015-08-17 15:04:09 +02005852 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005853 *
Michal Vaskobb211122015-08-19 14:03:11 +02005854 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005855 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005856 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005857 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005858 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005859static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005860resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005861{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005862 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005863 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005864 char *s = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005865 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005866
5867 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005868 assert(keys_str);
5869
Radek Krejci5c08a992016-11-02 13:30:04 +01005870 if (!list->child) {
5871 /* no child, possible forward reference */
Michal Vasko53b7da02018-02-13 15:28:42 +01005872 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Radek Krejci5c08a992016-11-02 13:30:04 +01005873 return EXIT_FAILURE;
5874 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005875 /* get the key name */
5876 if ((value = strpbrk(keys_str, " \t\n"))) {
5877 len = value - keys_str;
5878 while (isspace(value[0])) {
5879 value++;
5880 }
5881 } else {
5882 len = strlen(keys_str);
5883 }
5884
Radek Krejcia98048c2017-05-24 16:35:48 +02005885 if (list->keys[i]) {
5886 /* skip already resolved keys */
5887 goto next;
5888 }
5889
Michal Vaskobb520442017-05-23 10:55:18 +02005890 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5891 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005892 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005893 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005894 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005895 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005896
Radek Krejci48464ed2016-03-17 15:44:09 +01005897 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005898 /* check_key logs */
5899 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005900 }
5901
Radek Krejcicf509982015-12-15 09:22:44 +01005902 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005903 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005904 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5905 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005906 return -1;
5907 }
5908
Radek Krejcia98048c2017-05-24 16:35:48 +02005909 /* default value - is ignored, keep it but print a warning */
5910 if (list->keys[i]->dflt) {
5911 /* log is not hidden only in case this resolving fails and in such a case
5912 * we cannot get here
5913 */
Michal Vasko53b7da02018-02-13 15:28:42 +01005914 assert(log_opt == ILO_STORE);
5915 log_opt = ILO_LOG;
5916 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
Michal Vasko395b0a02018-01-22 09:36:20 +01005917 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
Michal Vasko53b7da02018-02-13 15:28:42 +01005918 log_opt = ILO_STORE;
Radek Krejcia98048c2017-05-24 16:35:48 +02005919 free(s);
5920 }
5921
5922next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005923 /* prepare for next iteration */
5924 while (value && isspace(value[0])) {
5925 value++;
5926 }
5927 keys_str = value;
5928 }
5929
Michal Vaskof02e3742015-08-05 16:27:02 +02005930 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005931}
5932
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005933/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005934 * @brief Resolve (check) all must conditions of \p node.
5935 * Logs directly.
5936 *
5937 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005938 * @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 +02005939 *
5940 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5941 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005942static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005943resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005944{
Michal Vaskobf19d252015-10-08 15:39:17 +02005945 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005946 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005947 struct lys_restr *must;
5948 struct lyxp_set set;
Michal Vasko53b7da02018-02-13 15:28:42 +01005949 struct ly_ctx *ctx = node->schema->module->ctx;
Michal Vaskobf19d252015-10-08 15:39:17 +02005950
5951 assert(node);
5952 memset(&set, 0, sizeof set);
5953
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005954 if (inout_parent) {
5955 for (schema = lys_parent(node->schema);
5956 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5957 schema = lys_parent(schema));
5958 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005959 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005960 return -1;
5961 }
5962 must_size = ((struct lys_node_inout *)schema)->must_size;
5963 must = ((struct lys_node_inout *)schema)->must;
5964
5965 /* context node is the RPC/action */
5966 node = node->parent;
5967 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005968 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005969 return -1;
5970 }
5971 } else {
5972 switch (node->schema->nodetype) {
5973 case LYS_CONTAINER:
5974 must_size = ((struct lys_node_container *)node->schema)->must_size;
5975 must = ((struct lys_node_container *)node->schema)->must;
5976 break;
5977 case LYS_LEAF:
5978 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5979 must = ((struct lys_node_leaf *)node->schema)->must;
5980 break;
5981 case LYS_LEAFLIST:
5982 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5983 must = ((struct lys_node_leaflist *)node->schema)->must;
5984 break;
5985 case LYS_LIST:
5986 must_size = ((struct lys_node_list *)node->schema)->must_size;
5987 must = ((struct lys_node_list *)node->schema)->must;
5988 break;
5989 case LYS_ANYXML:
5990 case LYS_ANYDATA:
5991 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5992 must = ((struct lys_node_anydata *)node->schema)->must;
5993 break;
5994 case LYS_NOTIF:
5995 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5996 must = ((struct lys_node_notif *)node->schema)->must;
5997 break;
5998 default:
5999 must_size = 0;
6000 break;
6001 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006002 }
6003
6004 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006005 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006006 return -1;
6007 }
6008
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006009 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02006010
Michal Vasko8146d4c2016-05-09 15:50:29 +02006011 if (!set.val.bool) {
Michal Vaskoc04173b2018-03-09 10:43:22 +01006012 if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006013 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
6014 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006015 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006016 if (must[i].emsg) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006017 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006018 }
6019 if (must[i].eapptag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006020 ly_err_last_set_apptag(ctx, must[i].eapptag);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006021 }
6022 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02006023 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006024 }
6025 }
6026
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006027 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02006028}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006029
Michal Vaskobf19d252015-10-08 15:39:17 +02006030/**
Michal Vasko508a50d2016-09-07 14:50:33 +02006031 * @brief Resolve (find) when condition schema context node. Does not log.
6032 *
6033 * @param[in] schema Schema node with the when condition.
6034 * @param[out] ctx_snode When schema context node.
6035 * @param[out] ctx_snode_type Schema context node type.
6036 */
6037void
6038resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
6039{
6040 const struct lys_node *sparent;
6041
6042 /* find a not schema-only node */
6043 *ctx_snode_type = LYXP_NODE_ELEM;
6044 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
6045 if (schema->nodetype == LYS_AUGMENT) {
6046 sparent = ((struct lys_node_augment *)schema)->target;
6047 } else {
6048 sparent = schema->parent;
6049 }
6050 if (!sparent) {
6051 /* context node is the document root (fake root in our case) */
6052 if (schema->flags & LYS_CONFIG_W) {
6053 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
6054 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02006055 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02006056 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02006057 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskocb45f472018-02-12 10:47:42 +01006058 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
Michal Vasko508a50d2016-09-07 14:50:33 +02006059 break;
6060 }
6061 schema = sparent;
6062 }
6063
6064 *ctx_snode = (struct lys_node *)schema;
6065}
6066
6067/**
Michal Vaskocf024702015-10-08 15:01:42 +02006068 * @brief Resolve (find) when condition context node. Does not log.
6069 *
6070 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02006071 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02006072 * @param[out] ctx_node Context node.
6073 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02006074 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02006075 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02006076 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02006077static int
6078resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
6079 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006080{
Michal Vaskocf024702015-10-08 15:01:42 +02006081 struct lyd_node *parent;
6082 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006083 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02006084 uint16_t i, data_depth, schema_depth;
6085
Michal Vasko508a50d2016-09-07 14:50:33 +02006086 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02006087
Michal Vaskofe989752016-09-08 08:47:26 +02006088 if (node_type == LYXP_NODE_ELEM) {
6089 /* standard element context node */
6090 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
6091 for (sparent = schema, schema_depth = 0;
6092 sparent;
6093 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
6094 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
6095 ++schema_depth;
6096 }
Michal Vaskocf024702015-10-08 15:01:42 +02006097 }
Michal Vaskofe989752016-09-08 08:47:26 +02006098 if (data_depth < schema_depth) {
6099 return -1;
6100 }
Michal Vaskocf024702015-10-08 15:01:42 +02006101
Michal Vasko956e8542016-08-26 09:43:35 +02006102 /* find the corresponding data node */
6103 for (i = 0; i < data_depth - schema_depth; ++i) {
6104 node = node->parent;
6105 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02006106 if (node->schema != schema) {
6107 return -1;
6108 }
Michal Vaskofe989752016-09-08 08:47:26 +02006109 } else {
6110 /* root context node */
6111 while (node->parent) {
6112 node = node->parent;
6113 }
6114 while (node->prev->next) {
6115 node = node->prev;
6116 }
Michal Vaskocf024702015-10-08 15:01:42 +02006117 }
6118
Michal Vaskoa59495d2016-08-22 09:18:58 +02006119 *ctx_node = node;
6120 *ctx_node_type = node_type;
6121 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02006122}
6123
Michal Vasko76c3bd32016-08-24 16:02:52 +02006124/**
6125 * @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 +01006126 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02006127 *
6128 * @param[in] snode Schema node, whose children instances need to be unlinked.
6129 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
6130 * it is moved to point to another sibling still in the original tree.
6131 * @param[in,out] ctx_node When context node, adjusted if needed.
6132 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
6133 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
6134 * Ordering may change, but there will be no semantic change.
6135 *
6136 * @return EXIT_SUCCESS on success, -1 on error.
6137 */
6138static int
6139resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
6140 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
6141{
6142 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006143 const struct lys_node *slast;
Michal Vasko53b7da02018-02-13 15:28:42 +01006144 struct ly_ctx *ctx = snode->module->ctx;
Michal Vasko76c3bd32016-08-24 16:02:52 +02006145
6146 switch (snode->nodetype) {
6147 case LYS_AUGMENT:
6148 case LYS_USES:
6149 case LYS_CHOICE:
6150 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006151 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01006152 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006153 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6154 continue;
6155 }
6156
6157 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006158 return -1;
6159 }
6160 }
6161 break;
6162 case LYS_CONTAINER:
6163 case LYS_LIST:
6164 case LYS_LEAF:
6165 case LYS_LEAFLIST:
6166 case LYS_ANYXML:
6167 case LYS_ANYDATA:
6168 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6169 if (elem->schema == snode) {
6170
6171 if (elem == *ctx_node) {
6172 /* We are going to unlink our context node! This normally cannot happen,
6173 * but we use normal top-level data nodes for faking a document root node,
6174 * so if this is the context node, we just use the next top-level node.
6175 * Additionally, it can even happen that there are no top-level data nodes left,
6176 * all were unlinked, so in this case we pass NULL as the context node/data tree,
6177 * lyxp_eval() can handle this special situation.
6178 */
6179 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006180 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006181 return -1;
6182 }
6183
6184 if (elem->prev == elem) {
6185 /* unlinking last top-level element, use an empty data tree */
6186 *ctx_node = NULL;
6187 } else {
6188 /* in this case just use the previous/last top-level data node */
6189 *ctx_node = elem->prev;
6190 }
6191 } else if (elem == *node) {
6192 /* We are going to unlink the currently processed node. This does not matter that
6193 * much, but we would lose access to the original data tree, so just move our
6194 * pointer somewhere still inside it.
6195 */
6196 if ((*node)->prev != *node) {
6197 *node = (*node)->prev;
6198 } else {
6199 /* the processed node with sibings were all unlinked, oh well */
6200 *node = NULL;
6201 }
6202 }
6203
6204 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01006205 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006206 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006207 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006208 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006209 return -1;
6210 }
6211 } else {
6212 *unlinked_nodes = elem;
6213 }
6214
6215 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6216 /* there can be only one instance */
6217 break;
6218 }
6219 }
6220 }
6221 break;
6222 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006223 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006224 return -1;
6225 }
6226
6227 return EXIT_SUCCESS;
6228}
6229
6230/**
6231 * @brief Relink the unlinked nodes back.
6232 *
6233 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6234 * we simply need a sibling from the original data tree.
6235 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6236 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6237 * or the sibling of \p unlinked_nodes.
6238 *
6239 * @return EXIT_SUCCESS on success, -1 on error.
6240 */
6241static int
6242resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6243{
6244 struct lyd_node *elem;
6245
6246 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006247 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006248 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006249 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006250 return -1;
6251 }
6252 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006253 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006254 return -1;
6255 }
6256 }
6257 }
6258
6259 return EXIT_SUCCESS;
6260}
6261
Radek Krejci03b71f72016-03-16 11:10:09 +01006262int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006263resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01006264{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006265 int ret = 0;
6266 uint8_t must_size;
6267 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02006268
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006269 assert(node);
6270
6271 schema = node->schema;
6272
6273 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02006274 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01006275 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006276 must_size = ((struct lys_node_container *)schema)->must_size;
6277 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006278 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006279 must_size = ((struct lys_node_leaf *)schema)->must_size;
6280 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006281 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006282 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6283 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006284 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006285 must_size = ((struct lys_node_list *)schema)->must_size;
6286 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006287 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02006288 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006289 must_size = ((struct lys_node_anydata *)schema)->must_size;
6290 break;
6291 case LYS_NOTIF:
6292 must_size = ((struct lys_node_notif *)schema)->must_size;
6293 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006294 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006295 must_size = 0;
6296 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006297 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006298
6299 if (must_size) {
6300 ++ret;
6301 }
6302
6303 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6304 if (!node->prev->next) {
6305 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6306 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6307 ret += 0x2;
6308 }
6309 }
6310
6311 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006312}
6313
6314int
Radek Krejci46165822016-08-26 14:06:27 +02006315resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006316{
Radek Krejci46165822016-08-26 14:06:27 +02006317 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006318
Radek Krejci46165822016-08-26 14:06:27 +02006319 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006320
Radek Krejci46165822016-08-26 14:06:27 +02006321 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006322 return 1;
6323 }
6324
Radek Krejci46165822016-08-26 14:06:27 +02006325 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006326 goto check_augment;
6327
Radek Krejci46165822016-08-26 14:06:27 +02006328 while (parent) {
6329 /* stop conditions */
6330 if (!mode) {
6331 /* stop on node that can be instantiated in data tree */
6332 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6333 break;
6334 }
6335 } else {
6336 /* stop on the specified node */
6337 if (parent == stop) {
6338 break;
6339 }
6340 }
6341
6342 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006343 return 1;
6344 }
6345check_augment:
6346
6347 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02006348 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006349 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006350 }
6351 parent = lys_parent(parent);
6352 }
6353
6354 return 0;
6355}
6356
Michal Vaskocf024702015-10-08 15:01:42 +02006357/**
6358 * @brief Resolve (check) all when conditions relevant for \p node.
6359 * Logs directly.
6360 *
6361 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02006362 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6363 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02006364 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006365 * @return
6366 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02006367 * 0 - all "when" statements true
6368 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01006369 * 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 +02006370 */
Radek Krejci46165822016-08-26 14:06:27 +02006371int
Michal Vasko0b963112017-08-11 12:45:36 +02006372resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02006373{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006374 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006375 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006376 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006377 enum lyxp_node_type ctx_node_type;
Michal Vasko53b7da02018-02-13 15:28:42 +01006378 struct ly_ctx *ctx = node->schema->module->ctx;
Radek Krejci51093642016-03-29 10:14:59 +02006379 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006380
6381 assert(node);
6382 memset(&set, 0, sizeof set);
6383
Michal Vasko78d97e22017-02-21 09:54:38 +01006384 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006385 /* make the node dummy for the evaluation */
6386 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006387 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
6388 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006389 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006390 if (rc) {
6391 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006392 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006393 }
Radek Krejci51093642016-03-29 10:14:59 +02006394 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006395 }
6396
Radek Krejci03b71f72016-03-16 11:10:09 +01006397 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006398 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006399 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006400 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006401 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006402 || ((((struct lys_node_container *)node->schema)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6403 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006404 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6405 ((struct lys_node_container *)node->schema)->when->cond);
6406 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006407 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006408 if (failed_when) {
6409 *failed_when = ((struct lys_node_container *)node->schema)->when;
6410 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006411 goto cleanup;
6412 }
Michal Vaskocf024702015-10-08 15:01:42 +02006413 }
Radek Krejci51093642016-03-29 10:14:59 +02006414
6415 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006416 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006417 }
6418
Michal Vasko90fc2a32016-08-24 15:58:58 +02006419 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006420 goto check_augment;
6421
6422 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006423 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6424 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006425 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006426 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006427 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006428 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006429 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006430 }
6431 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006432
6433 unlinked_nodes = NULL;
6434 /* we do not want our node pointer to change */
6435 tmp_node = node;
6436 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6437 if (rc) {
6438 goto cleanup;
6439 }
6440
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006441 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6442 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006443
6444 if (unlinked_nodes && ctx_node) {
6445 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6446 rc = -1;
6447 goto cleanup;
6448 }
6449 }
6450
Radek Krejci03b71f72016-03-16 11:10:09 +01006451 if (rc) {
6452 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006453 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006454 }
Radek Krejci51093642016-03-29 10:14:59 +02006455 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006456 }
6457
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006458 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006459 if (!set.val.bool) {
Michal Vasko0b963112017-08-11 12:45:36 +02006460 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006461 || ((((struct lys_node_uses *)sparent)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6462 || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006463 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6464 ((struct lys_node_uses *)sparent)->when->cond);
6465 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006466 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko53b7da02018-02-13 15:28:42 +01006467 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006468 if (failed_when) {
6469 *failed_when = ((struct lys_node_uses *)sparent)->when;
6470 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006471 goto cleanup;
6472 }
Michal Vaskocf024702015-10-08 15:01:42 +02006473 }
Radek Krejci51093642016-03-29 10:14:59 +02006474
6475 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006476 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006477 }
6478
6479check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006480 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006481 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006482 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006483 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006484 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006485 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006486 }
6487 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006488
6489 unlinked_nodes = NULL;
6490 tmp_node = node;
6491 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6492 if (rc) {
6493 goto cleanup;
6494 }
6495
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006496 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6497 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006498
6499 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6500 * so the tree did not actually change and there is nothing for us to do
6501 */
6502 if (unlinked_nodes && ctx_node) {
6503 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6504 rc = -1;
6505 goto cleanup;
6506 }
6507 }
6508
Radek Krejci03b71f72016-03-16 11:10:09 +01006509 if (rc) {
6510 if (rc == 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006511 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006512 }
Radek Krejci51093642016-03-29 10:14:59 +02006513 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006514 }
6515
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006516 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006517 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006518 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko0b963112017-08-11 12:45:36 +02006519 if ((ignore_fail == 1)
Michal Vaskoc04173b2018-03-09 10:43:22 +01006520 || ((((struct lys_node_augment *)sparent->parent)->when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6521 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006522 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006523 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006524 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006525 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006526 if (failed_when) {
6527 *failed_when = ((struct lys_node_augment *)sparent->parent)->when;
6528 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006529 goto cleanup;
6530 }
Michal Vaskocf024702015-10-08 15:01:42 +02006531 }
Radek Krejci51093642016-03-29 10:14:59 +02006532
6533 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006534 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006535 }
6536
Michal Vasko90fc2a32016-08-24 15:58:58 +02006537 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006538 }
6539
Radek Krejci0b7704f2016-03-18 12:16:14 +01006540 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006541
Radek Krejci51093642016-03-29 10:14:59 +02006542cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006543 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006544 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006545 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006546}
6547
Radek Krejcicbb473e2016-09-16 14:48:32 +02006548static int
6549check_leafref_features(struct lys_type *type)
6550{
6551 struct lys_node *iter;
6552 struct ly_set *src_parents, *trg_parents, *features;
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006553 struct lys_node_augment *aug;
Michal Vasko53b7da02018-02-13 15:28:42 +01006554 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006555 unsigned int i, j, size, x;
6556 int ret = EXIT_SUCCESS;
6557
6558 assert(type->parent);
6559
6560 src_parents = ly_set_new();
6561 trg_parents = ly_set_new();
6562 features = ly_set_new();
6563
6564 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006565 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006566 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6567 continue;
6568 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006569 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006570 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006571 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006572 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006573 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006574 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006575 ret = EXIT_FAILURE;
6576 goto cleanup;
6577 }
6578 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006579 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6580 }
6581 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006582 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006583 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6584 continue;
6585 }
Michal Vaskoe9212852017-11-21 13:41:43 +01006586 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006587 aug = (struct lys_node_augment *)iter->parent;
Michal Vaskoe9212852017-11-21 13:41:43 +01006588 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006589 /* unresolved augment, wait until it's resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01006590 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
Michal Vaskobd026102017-11-21 13:43:01 +01006591 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006592 ret = EXIT_FAILURE;
6593 goto cleanup;
6594 }
6595 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006596 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6597 }
6598
6599 /* compare the features used in if-feature statements in the rest of both
6600 * chains of parents. The set of features used for target must be a subset
6601 * of features used for the leafref. This is not a perfect, we should compare
6602 * the truth tables but it could require too much resources, so we simplify that */
6603 for (i = 0; i < src_parents->number; i++) {
6604 iter = src_parents->set.s[i]; /* shortcut */
6605 if (!iter->iffeature_size) {
6606 continue;
6607 }
6608 for (j = 0; j < iter->iffeature_size; j++) {
6609 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6610 for (; size; size--) {
6611 if (!iter->iffeature[j].features[size - 1]) {
6612 /* not yet resolved feature, postpone this check */
6613 ret = EXIT_FAILURE;
6614 goto cleanup;
6615 }
6616 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6617 }
6618 }
6619 }
6620 x = features->number;
6621 for (i = 0; i < trg_parents->number; i++) {
6622 iter = trg_parents->set.s[i]; /* shortcut */
6623 if (!iter->iffeature_size) {
6624 continue;
6625 }
6626 for (j = 0; j < iter->iffeature_size; j++) {
6627 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6628 for (; size; size--) {
6629 if (!iter->iffeature[j].features[size - 1]) {
6630 /* not yet resolved feature, postpone this check */
6631 ret = EXIT_FAILURE;
6632 goto cleanup;
6633 }
Michal Vasko53b7da02018-02-13 15:28:42 +01006634 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006635 /* the feature is not present in features set of target's parents chain */
Michal Vasko53b7da02018-02-13 15:28:42 +01006636 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
6637 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006638 "Leafref is not conditional based on \"%s\" feature as its target.",
6639 iter->iffeature[j].features[size - 1]->name);
6640 ret = -1;
6641 goto cleanup;
6642 }
6643 }
6644 }
6645 }
6646
6647cleanup:
6648 ly_set_free(features);
6649 ly_set_free(src_parents);
6650 ly_set_free(trg_parents);
6651
6652 return ret;
6653}
6654
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006655static int
6656check_type_union_leafref(struct lys_type *type)
6657{
6658 uint8_t i;
6659
6660 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6661 /* go through unions and look for leafref */
6662 for (i = 0; i < type->info.uni.count; ++i) {
6663 switch (type->info.uni.types[i].base) {
6664 case LY_TYPE_LEAFREF:
6665 return 1;
6666 case LY_TYPE_UNION:
6667 if (check_type_union_leafref(&type->info.uni.types[i])) {
6668 return 1;
6669 }
6670 break;
6671 default:
6672 break;
6673 }
6674 }
6675
6676 return 0;
6677 }
6678
6679 /* just inherit the flag value */
6680 return type->der->has_union_leafref;
6681}
6682
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006683/**
Michal Vaskobb211122015-08-19 14:03:11 +02006684 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006685 *
6686 * @param[in] mod Main module.
6687 * @param[in] item Item to resolve. Type determined by \p type.
6688 * @param[in] type Type of the unresolved item.
6689 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006690 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006691 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006692 *
6693 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6694 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006695static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006696resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006697 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006698{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006699 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Michal Vasko53b7da02018-02-13 15:28:42 +01006700 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006701 unsigned int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01006702 struct ly_ctx * ctx = mod->ctx;
Radek Krejci80056d52017-01-05 13:13:33 +01006703 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006704 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006705 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006706
Radek Krejcic79c6b12016-07-26 15:11:49 +02006707 struct ly_set *refs, *procs;
6708 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006709 struct lys_ident *ident;
6710 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006711 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006712 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006713 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006714 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006715 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006716 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006717 struct lys_ext_instance *ext, **extlist;
6718 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006719
6720 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006721 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006722 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006723 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006724 ident = item;
6725
Radek Krejci018f1f52016-08-03 16:01:20 +02006726 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006727 break;
6728 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006729 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006730 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006731 stype = item;
6732
Radek Krejci018f1f52016-08-03 16:01:20 +02006733 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006734 break;
6735 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006736 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006737 stype = item;
6738
Michal Vasko1c007172017-03-10 10:20:44 +01006739 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6740 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006741 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006742
Michal Vaskobb520442017-05-23 10:55:18 +02006743 if (lys_node_module(node)->implemented) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006744 /* make all the modules in the path implemented */
Michal Vaskobb520442017-05-23 10:55:18 +02006745 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6746 if (!lys_node_module(next)->implemented) {
6747 if (lys_set_implemented(lys_node_module(next))) {
6748 rc = -1;
6749 break;
6750 }
6751 }
6752 }
6753 if (next) {
6754 break;
6755 }
6756
6757 /* store the backlink from leafref target */
6758 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6759 rc = -1;
Michal Vaskobe136f62017-09-21 12:08:39 +02006760 break;
6761 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006762 }
Michal Vaskof1aa47d2017-09-21 12:09:29 +02006763
6764 /* check if leafref and its target are under common if-features */
6765 rc = check_leafref_features(stype);
Radek Krejci46c4cd72016-01-21 15:13:52 +01006766 }
6767
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006768 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006769 case UNRES_TYPE_DER_EXT:
6770 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006771 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006772 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006773 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006774 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006775 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006776 /* parent */
6777 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006778 stype = item;
6779
Michal Vasko88c29542015-11-27 14:57:53 +01006780 /* HACK type->der is temporarily unparsed type statement */
6781 yin = (struct lyxml_elem *)stype->der;
6782 stype->der = NULL;
6783
Pavol Vicana0e4e672016-02-24 12:20:04 +01006784 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6785 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006786 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006787
6788 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006789 /* may try again later */
6790 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006791 } else {
6792 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006793 lydict_remove(ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006794 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006795 }
6796
Michal Vasko88c29542015-11-27 14:57:53 +01006797 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006798 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006799 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006800 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006801 lyxml_free(ctx, yin);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006802 } else {
6803 /* may try again later, put all back how it was */
6804 stype->der = (struct lys_tpdf *)yin;
6805 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006806 }
Radek Krejcic13db382016-08-16 10:52:42 +02006807 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006808 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006809 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006810 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
Radek Krejci2c2fce82016-08-01 13:52:26 +02006811 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006812
6813 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6814 /* fill typedef union leafref flag */
6815 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6816 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6817 /* copy the type in case it has union leafref flag */
6818 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006819 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006820 return -1;
6821 }
6822 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02006823 } else if (rc == EXIT_FAILURE && !(stype->flags & LYTYPE_GRP)) {
Radek Krejcic13db382016-08-16 10:52:42 +02006824 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6825 * 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 +02006826 * grouping. The grouping cannot be used unless the unres counter is 0.
Michal Vasko70bf8e52018-03-26 11:32:33 +02006827 * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006828 * of the type's base member. */
6829 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6830 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006831 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006832 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006833 return -1;
6834 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02006835 stype->flags |= LYTYPE_GRP;
Radek Krejcic13db382016-08-16 10:52:42 +02006836 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006837 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006838 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006839 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006840 iff_data = str_snode;
6841 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006842 if (!rc) {
6843 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006844 if (iff_data->infeature) {
6845 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6846 feat = *((struct lys_feature **)item);
6847 if (!feat->depfeatures) {
6848 feat->depfeatures = ly_set_new();
6849 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006850 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006851 }
6852 /* cleanup temporary data */
Michal Vasko53b7da02018-02-13 15:28:42 +01006853 lydict_remove(ctx, iff_data->fname);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006854 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006855 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006856 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006857 case UNRES_FEATURE:
6858 feat = (struct lys_feature *)item;
6859
6860 if (feat->iffeature_size) {
6861 refs = ly_set_new();
6862 procs = ly_set_new();
6863 ly_set_add(procs, feat, 0);
6864
6865 while (procs->number) {
6866 ref = procs->set.g[procs->number - 1];
6867 ly_set_rm_index(procs, procs->number - 1);
6868
6869 for (i = 0; i < ref->iffeature_size; i++) {
6870 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6871 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006872 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006873 if (ref->iffeature[i].features[j - 1] == feat) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006874 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006875 goto featurecheckdone;
6876 }
6877
6878 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6879 k = refs->number;
6880 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6881 /* not yet seen feature, add it for processing */
6882 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6883 }
6884 }
6885 } else {
6886 /* forward reference */
6887 rc = EXIT_FAILURE;
6888 goto featurecheckdone;
6889 }
6890 }
6891
6892 }
6893 }
6894 rc = EXIT_SUCCESS;
6895
6896featurecheckdone:
6897 ly_set_free(refs);
6898 ly_set_free(procs);
6899 }
6900
6901 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006902 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006903 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006904 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006905 case UNRES_TYPEDEF_DFLT:
6906 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006907 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006908 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006909 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006910 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006911 break;
6912 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006913 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006914 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006915 choic = item;
6916
Radek Krejcie00d2312016-08-12 15:27:49 +02006917 if (!choic->dflt) {
6918 choic->dflt = resolve_choice_dflt(choic, expr);
6919 }
Michal Vasko7955b362015-09-04 14:18:15 +02006920 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006921 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006922 } else {
6923 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006924 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006925 break;
6926 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006927 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006928 break;
6929 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006930 unique_info = (struct unres_list_uniq *)item;
6931 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006932 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006933 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006934 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006935 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006936 case UNRES_XPATH:
6937 node = (struct lys_node *)item;
Michal Vasko895c11f2018-03-12 11:35:58 +01006938 rc = check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02006939 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006940 case UNRES_EXT:
6941 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006942 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006943 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006944 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006945 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006946 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006947 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006948 if (eplugin) {
6949 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006950 u = malloc(sizeof *u);
Michal Vasko53b7da02018-02-13 15:28:42 +01006951 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006952 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006953 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6954 /* something really bad happend since the extension finalization is not actually
6955 * being resolved while adding into unres, so something more serious with the unres
6956 * list itself must happened */
6957 return -1;
6958 }
Radek Krejci80056d52017-01-05 13:13:33 +01006959 }
6960 }
Radek Krejci79685c92017-02-17 10:49:43 +01006961 }
6962 if (!rc || rc == -1) {
6963 /* cleanup on success or fatal error */
6964 if (ext_data->datatype == LYS_IN_YIN) {
6965 /* YIN */
Michal Vasko53b7da02018-02-13 15:28:42 +01006966 lyxml_free(ctx, ext_data->data.yin);
Radek Krejci79685c92017-02-17 10:49:43 +01006967 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006968 /* YANG */
6969 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006970 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006971 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006972 }
6973 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006974 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006975 u = (uint8_t *)str_snode;
6976 ext = (*(struct lys_ext_instance ***)item)[*u];
6977 free(u);
6978
Radek Krejci80056d52017-01-05 13:13:33 +01006979 eplugin = ext->def->plugin;
6980
6981 /* inherit */
6982 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6983 root = (struct lys_node *)ext->parent;
6984 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6985 LY_TREE_DFS_BEGIN(root->child, next, node) {
6986 /* first, check if the node already contain instance of the same extension,
6987 * in such a case we won't inherit. In case the node was actually defined as
6988 * augment data, we are supposed to check the same way also the augment node itself */
6989 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6990 goto inherit_dfs_sibling;
6991 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6992 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6993 goto inherit_dfs_sibling;
6994 }
6995
6996 if (eplugin->check_inherit) {
6997 /* we have a callback to check the inheritance, use it */
6998 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6999 case 0:
7000 /* yes - continue with the inheriting code */
7001 break;
7002 case 1:
7003 /* no - continue with the node's sibling */
7004 goto inherit_dfs_sibling;
7005 case 2:
7006 /* no, but continue with the children, just skip the inheriting code for this node */
7007 goto inherit_dfs_child;
7008 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007009 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
Radek Krejci80056d52017-01-05 13:13:33 +01007010 ext->def->module->name, ext->def->name, rc);
7011 }
7012 }
7013
7014 /* inherit the extension */
7015 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Michal Vasko53b7da02018-02-13 15:28:42 +01007016 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007017 extlist[node->ext_size] = malloc(sizeof **extlist);
Michal Vasko53b7da02018-02-13 15:28:42 +01007018 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007019 memcpy(extlist[node->ext_size], ext, sizeof *ext);
7020 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
7021
7022 node->ext = extlist;
7023 node->ext_size++;
7024
7025inherit_dfs_child:
7026 /* modification of - select element for the next run - children first */
7027 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
7028 next = NULL;
7029 } else {
7030 next = node->child;
7031 }
7032 if (!next) {
7033inherit_dfs_sibling:
7034 /* no children, try siblings */
7035 next = node->next;
7036 }
7037 while (!next) {
7038 /* go to the parent */
7039 node = lys_parent(node);
7040
7041 /* we are done if we are back in the root (the starter's parent */
7042 if (node == root) {
7043 break;
7044 }
7045
7046 /* parent is already processed, go to its sibling */
7047 next = node->next;
7048 }
7049 }
7050 }
7051 }
7052
7053 /* final check */
7054 if (eplugin->check_result) {
7055 if ((*eplugin->check_result)(ext)) {
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007056 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
Radek Krejci80056d52017-01-05 13:13:33 +01007057 return -1;
7058 }
7059 }
7060
7061 rc = 0;
7062 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007063 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007064 LOGINT(ctx);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007065 break;
7066 }
7067
Radek Krejci54081ce2016-08-12 15:21:47 +02007068 if (has_str && !rc) {
7069 /* the string is no more needed in case of success.
7070 * In case of forward reference, we will try to resolve the string later */
Michal Vasko53b7da02018-02-13 15:28:42 +01007071 lydict_remove(ctx, str_snode);
Radek Krejci4f78b532016-02-17 13:43:00 +01007072 }
7073
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007074 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007075}
7076
Michal Vaskof02e3742015-08-05 16:27:02 +02007077/* logs directly */
7078static void
Radek Krejci48464ed2016-03-17 15:44:09 +01007079print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007080{
Michal Vaskocb34dc62016-05-20 14:38:37 +02007081 struct lyxml_elem *xml;
7082 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007083 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01007084 const char *name = NULL;
7085 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007086
Michal Vaskof02e3742015-08-05 16:27:02 +02007087 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02007088 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007089 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007090 break;
7091 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007092 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007093 break;
7094 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007095 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
7096 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02007097 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01007098 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02007099 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02007100 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02007101 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
7102 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01007103 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007104 } else {
7105 LY_TREE_FOR(xml->attr, attr) {
7106 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01007107 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007108 break;
7109 }
7110 }
7111 assert(attr);
7112 }
Radek Krejcie534c132016-11-23 13:32:31 +01007113 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007114 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007115 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007116 iff_data = str_node;
7117 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02007118 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02007119 case UNRES_FEATURE:
7120 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
7121 ((struct lys_feature *)item)->name);
7122 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007123 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01007124 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007125 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01007126 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02007127 case UNRES_TYPE_DFLT:
Michal Vaskoba835cd2018-02-23 09:25:48 +01007128 if (*(char **)str_node) {
7129 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
Radek Krejci2e2de832016-10-13 16:12:26 +02007130 } /* else no default value in the type itself, but we are checking some restrictions against
7131 * possible default value of some base type. The failure is caused by not resolved base type,
7132 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02007133 break;
7134 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007135 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007136 break;
7137 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01007138 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007139 break;
7140 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01007141 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007142 break;
Michal Vasko7178e692016-02-12 15:58:05 +01007143 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007144 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
7145 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01007146 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02007147 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01007148 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
7149 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02007150 break;
Radek Krejcie534c132016-11-23 13:32:31 +01007151 case UNRES_EXT:
7152 extinfo = (struct unres_ext *)str_node;
7153 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7154 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7155 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007156 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007157 LOGINT(NULL);
Michal Vaskof02e3742015-08-05 16:27:02 +02007158 break;
7159 }
7160}
7161
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007162/**
Michal Vaskobb211122015-08-19 14:03:11 +02007163 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007164 *
7165 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007166 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007167 *
Michal Vasko92b8a382015-08-19 14:03:49 +02007168 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007169 */
Michal Vaskof02e3742015-08-05 16:27:02 +02007170int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007171resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02007172{
Radek Krejci010e54b2016-03-15 09:40:34 +01007173 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko53b7da02018-02-13 15:28:42 +01007174 struct ly_err_item *prev_eitem;
7175 enum int_log_opts prev_ilo;
7176 LY_ERR prev_ly_errno;
7177 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007178
7179 assert(unres);
7180
Michal Vaskoe8734262016-09-29 14:12:06 +02007181 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko53b7da02018-02-13 15:28:42 +01007182 prev_ly_errno = ly_errno;
7183 ly_ilo_change(mod->ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02007184
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007185 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02007186 do {
Michal Vasko88c29542015-11-27 14:57:53 +01007187 unres_count = 0;
7188 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02007189
7190 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02007191 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02007192 * if-features are resolved here to make sure that we will have all if-features for
7193 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02007194 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02007195 continue;
7196 }
Radek Krejci018f1f52016-08-03 16:01:20 +02007197 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01007198 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02007199
Michal Vasko88c29542015-11-27 14:57:53 +01007200 ++unres_count;
Michal Vaskof96dfb62017-08-17 12:23:49 +02007201 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007202 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02007203 unres->type[i] = UNRES_RESOLVED;
7204 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01007205 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02007206 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007207 goto error;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007208 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007209 /* forward reference, erase errors */
7210 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vasko51054ca2015-08-12 12:20:00 +02007211 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007212 }
Michal Vasko88c29542015-11-27 14:57:53 +01007213 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02007214
Michal Vasko88c29542015-11-27 14:57:53 +01007215 if (res_count < unres_count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007216 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7217 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02007218
7219 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02007220 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02007221 continue;
7222 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02007223 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko22af5ca2016-05-20 11:44:02 +02007224 }
Michal Vasko92b8a382015-08-19 14:03:49 +02007225 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007226 }
7227
Michal Vaskof96dfb62017-08-17 12:23:49 +02007228 /* the rest except finalizing extensions and xpath */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007229 for (i = 0; i < unres->count; ++i) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02007230 if ((unres->type[i] == UNRES_RESOLVED) || (unres->type[i] == UNRES_EXT_FINALIZE) || (unres->type[i] == UNRES_XPATH)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007231 continue;
7232 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02007233
Michal Vaskof96dfb62017-08-17 12:23:49 +02007234 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01007235 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02007236 if (unres->type[i] == UNRES_LIST_UNIQ) {
7237 /* free the allocated structure */
7238 free(unres->item[i]);
7239 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007240 unres->type[i] = UNRES_RESOLVED;
7241 ++resolved;
7242 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007243 goto error;
Radek Krejci791f6c72017-02-22 15:23:39 +01007244 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007245 /* forward reference, erase errors */
7246 ly_err_free_next(mod->ctx, prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007247 }
7248 }
7249
Michal Vasko53b7da02018-02-13 15:28:42 +01007250 /* log normally now */
7251 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 0);
7252 ly_errno = prev_ly_errno;
Radek Krejci010e54b2016-03-15 09:40:34 +01007253
Radek Krejci80056d52017-01-05 13:13:33 +01007254 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7255 for (i = 0; i < unres->count; ++i) {
7256 if (unres->type[i] != UNRES_EXT_FINALIZE) {
7257 continue;
7258 }
7259
Michal Vaskof96dfb62017-08-17 12:23:49 +02007260 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci791f6c72017-02-22 15:23:39 +01007261 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01007262 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01007263 ++resolved;
7264 }
Radek Krejci791f6c72017-02-22 15:23:39 +01007265 /* else error - it was already printed, but resolved was not increased,
7266 so this unres item will not be resolved again in the following code,
7267 but it will cause returning -1 at the end, this way we are able to
7268 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01007269 }
7270
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007271 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007272 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
Michal Vaskof96dfb62017-08-17 12:23:49 +02007273 * all the validation errors, xpath is resolved only here to properly print all the messages
Radek Krejci010e54b2016-03-15 09:40:34 +01007274 */
7275 for (i = 0; i < unres->count; ++i) {
7276 if (unres->type[i] == UNRES_RESOLVED) {
7277 continue;
7278 }
Michal Vaskof96dfb62017-08-17 12:23:49 +02007279 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejcib3142312016-11-09 11:04:12 +01007280 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01007281 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01007282 unres->type[i] = UNRES_RESOLVED;
7283 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01007284 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007285 }
Radek Krejcib3142312016-11-09 11:04:12 +01007286 if (resolved < unres->count) {
7287 return -1;
7288 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007289 }
7290
Michal Vaskoe8734262016-09-29 14:12:06 +02007291 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01007292 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007293 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01007294
7295error:
7296 ly_ilo_restore(mod->ctx, prev_ilo, prev_eitem, 1);
7297 /* ly_errno will be set accordingly, we do not want to keep the previous value */
7298 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007299}
7300
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007301/**
Michal Vaskobb211122015-08-19 14:03:11 +02007302 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007303 *
7304 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007305 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007306 * @param[in] item Item to resolve. Type determined by \p type.
7307 * @param[in] type Type of the unresolved item.
7308 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007309 *
Michal Vasko3767fb22016-07-21 12:10:57 +02007310 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007311 */
7312int
Radek Krejci48464ed2016-03-17 15:44:09 +01007313unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7314 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007315{
Radek Krejci54081ce2016-08-12 15:21:47 +02007316 int rc;
7317 const char *dictstr;
7318
7319 dictstr = lydict_insert(mod->ctx, str, 0);
7320 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7321
Radek Krejcid9c0ce22017-01-20 15:20:16 +01007322 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02007323 lydict_remove(mod->ctx, dictstr);
7324 }
7325 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007326}
7327
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007328/**
Michal Vaskobb211122015-08-19 14:03:11 +02007329 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007330 *
7331 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007332 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007333 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01007334 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007335 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007336 *
Radek Krejci62f7aad2017-10-26 14:53:52 +02007337 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007338 */
7339int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007340unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01007341 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007342{
Michal Vasko53b7da02018-02-13 15:28:42 +01007343 int rc;
Radek Krejci62f7aad2017-10-26 14:53:52 +02007344 uint32_t u;
Michal Vasko53b7da02018-02-13 15:28:42 +01007345 enum int_log_opts prev_ilo;
7346 struct ly_err_item *prev_eitem;
7347 LY_ERR prev_ly_errno;
Michal Vasko88c29542015-11-27 14:57:53 +01007348 struct lyxml_elem *yin;
Michal Vasko53b7da02018-02-13 15:28:42 +01007349 struct ly_ctx *ctx = mod->ctx;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007350
Michal Vasko9bf425b2015-10-22 11:42:03 +02007351 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
7352 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007353
Radek Krejci850a5de2016-11-08 14:06:40 +01007354 /* check for duplicities in unres */
7355 for (u = 0; u < unres->count; u++) {
7356 if (unres->type[u] == type && unres->item[u] == item &&
7357 unres->str_snode[u] == snode && unres->module[u] == mod) {
Radek Krejci62f7aad2017-10-26 14:53:52 +02007358 /* duplication can happen when the node contains multiple statements of the same type to check,
7359 * this can happen for example when refinement is being applied, so we just postpone the processing
7360 * and do not duplicate the information */
7361 return EXIT_FAILURE;
Radek Krejci850a5de2016-11-08 14:06:40 +01007362 }
7363 }
7364
Michal Vaskof96dfb62017-08-17 12:23:49 +02007365 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH)) {
7366 /* extension finalization is not even tried when adding the item into the inres list,
7367 * xpath is not tried because it would hide some potential warnings */
Radek Krejcic293bac2017-02-27 11:25:28 +01007368 rc = EXIT_FAILURE;
7369 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007370 prev_ly_errno = ly_errno;
7371 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007372
Michal Vasko53b7da02018-02-13 15:28:42 +01007373 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01007374 if (rc != EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007375 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7376 if (rc != -1) {
7377 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007378 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007379
Radek Krejci80056d52017-01-05 13:13:33 +01007380 if (type == UNRES_LIST_UNIQ) {
7381 /* free the allocated structure */
7382 free(item);
7383 } else if (rc == -1 && type == UNRES_IFFEAT) {
7384 /* free the allocated resources */
7385 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007386 }
Radek Krejci80056d52017-01-05 13:13:33 +01007387 return rc;
7388 } else {
7389 /* erase info about validation errors */
Michal Vasko53b7da02018-02-13 15:28:42 +01007390 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7391 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007392 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007393
Radek Krejci80056d52017-01-05 13:13:33 +01007394 print_unres_schema_item_fail(item, type, snode);
7395
7396 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7397 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7398 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7399 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7400 lyxml_unlink_elem(mod->ctx, yin, 1);
7401 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7402 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007403 }
Michal Vasko88c29542015-11-27 14:57:53 +01007404 }
7405
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007406 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007407 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Michal Vasko53b7da02018-02-13 15:28:42 +01007408 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007409 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007410 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007411 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007412 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007413 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko53b7da02018-02-13 15:28:42 +01007414 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007415 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007416 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01007417 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007418 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007419
Michal Vasko3767fb22016-07-21 12:10:57 +02007420 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007421}
7422
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007423/**
Michal Vaskobb211122015-08-19 14:03:11 +02007424 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007425 *
7426 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007427 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007428 * @param[in] item Old item to be resolved.
7429 * @param[in] type Type of the old unresolved item.
7430 * @param[in] new_item New item to use in the duplicate.
7431 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007432 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007433 */
Michal Vaskodad19402015-08-06 09:51:53 +02007434int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007435unres_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 +02007436{
7437 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007438 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007439 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007440
Michal Vaskocf024702015-10-08 15:01:42 +02007441 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007442
Radek Krejcid09d1a52016-08-11 14:05:45 +02007443 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7444 if (type == UNRES_LIST_UNIQ) {
7445 aux_uniq.list = item;
7446 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7447 item = &aux_uniq;
7448 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007449 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007450
7451 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007452 if (type == UNRES_LIST_UNIQ) {
7453 free(new_item);
7454 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007455 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007456 }
7457
Radek Krejcic79c6b12016-07-26 15:11:49 +02007458 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007459 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007460 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007461 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007462 return -1;
7463 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007464 } else if (type == UNRES_IFFEAT) {
7465 /* duplicate unres_iffeature_data */
7466 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01007467 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007468 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7469 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7470 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007471 LOGINT(mod->ctx);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007472 return -1;
7473 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007474 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007475 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007476 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007477 return -1;
7478 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007479 }
Michal Vaskodad19402015-08-06 09:51:53 +02007480
7481 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007482}
7483
Michal Vaskof02e3742015-08-05 16:27:02 +02007484/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007485int
Michal Vasko878e38d2016-09-05 12:17:53 +02007486unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007487{
Michal Vasko878e38d2016-09-05 12:17:53 +02007488 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007489 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007490
Radek Krejciddddd0d2017-01-20 15:20:46 +01007491 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007492 i = start_on_backwards;
7493 } else {
7494 i = unres->count - 1;
7495 }
7496 for (; i > -1; i--) {
7497 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007498 continue;
7499 }
7500 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007501 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007502 break;
7503 }
7504 } else {
7505 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7506 aux_uniq2 = (struct unres_list_uniq *)item;
7507 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007508 break;
7509 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007510 }
7511 }
7512
Michal Vasko878e38d2016-09-05 12:17:53 +02007513 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007514}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007515
Michal Vaskoede9c472016-06-07 09:38:15 +02007516static void
7517unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7518{
7519 struct lyxml_elem *yin;
7520 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007521 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007522
7523 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007524 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007525 case UNRES_TYPE_DER:
7526 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7527 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7528 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007529 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007530 lydict_remove(ctx, yang->name);
7531 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007532 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7533 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7534 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007535 } else {
7536 lyxml_free(ctx, yin);
7537 }
7538 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007539 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007540 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7541 lydict_remove(ctx, iff_data->fname);
7542 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007543 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007544 case UNRES_IDENT:
7545 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007546 case UNRES_CHOICE_DFLT:
7547 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007548 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7549 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007550 case UNRES_LIST_UNIQ:
7551 free(unres->item[i]);
7552 break;
PavolVicanc1807262017-01-31 18:00:27 +01007553 case UNRES_EXT:
7554 free(unres->str_snode[i]);
7555 break;
PavolVicanfcc98762017-09-01 15:51:39 +02007556 case UNRES_EXT_FINALIZE:
7557 free(unres->str_snode[i]);
Michal Vaskoede9c472016-06-07 09:38:15 +02007558 default:
7559 break;
7560 }
7561 unres->type[i] = UNRES_RESOLVED;
7562}
7563
Michal Vasko88c29542015-11-27 14:57:53 +01007564void
Michal Vasko44ab1462017-05-18 13:18:36 +02007565unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007566{
7567 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007568 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007569
Radek Krejcic071c542016-01-27 14:57:51 +01007570 if (!unres || !(*unres)) {
7571 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007572 }
7573
Michal Vasko44ab1462017-05-18 13:18:36 +02007574 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007575
7576 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007577 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007578 if ((*unres)->type[i] != UNRES_RESOLVED) {
7579 unresolved++;
7580 }
7581 continue;
7582 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007583
7584 /* free heap memory for the specific item */
7585 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007586 }
7587
Michal Vaskoede9c472016-06-07 09:38:15 +02007588 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007589 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007590 free((*unres)->item);
7591 free((*unres)->type);
7592 free((*unres)->str_snode);
7593 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007594 free((*unres));
7595 (*unres) = NULL;
7596 }
Michal Vasko88c29542015-11-27 14:57:53 +01007597}
7598
Michal Vaskoff690e72017-08-03 14:25:07 +02007599/* check whether instance-identifier points outside its data subtree (for operation it is any node
7600 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007601static int
7602check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7603{
Michal Vaskoff690e72017-08-03 14:25:07 +02007604 const struct lys_node *op_node, *first_node;
Michal Vasko53b7da02018-02-13 15:28:42 +01007605 enum int_log_opts prev_ilo;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007606 char *buf;
Michal Vasko53b7da02018-02-13 15:28:42 +01007607 int ret = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007608
Radek Krejci034cb102017-08-01 15:45:13 +02007609 if (!json_instid || !json_instid[0]) {
7610 /* no/empty value */
7611 return 0;
7612 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007613
7614 for (op_node = lys_parent(sleaf);
7615 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7616 op_node = lys_parent(op_node));
7617
7618 if (op_node && lys_parent(op_node)) {
7619 /* nested operation - any absolute path is external */
7620 return 1;
7621 }
7622
7623 /* get the first node from the instid */
7624 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7625 if (!buf) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007626 /* so that we do not have to bother with logging, say it is not external */
7627 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007628 }
7629
Michal Vaskoff690e72017-08-03 14:25:07 +02007630 /* find the first schema node, do not log */
Michal Vasko53b7da02018-02-13 15:28:42 +01007631 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoff690e72017-08-03 14:25:07 +02007632 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
Michal Vasko53b7da02018-02-13 15:28:42 +01007633 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007634
Michal Vasko53b7da02018-02-13 15:28:42 +01007635 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007636 if (!first_node) {
7637 /* unknown path, say it is not external */
Michal Vaskoff690e72017-08-03 14:25:07 +02007638 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007639 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007640
7641 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7642
Michal Vaskoff690e72017-08-03 14:25:07 +02007643 if (op_node && (op_node != first_node)) {
7644 /* it is a top-level operation, so we're good if it points somewhere inside it */
7645 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007646 }
7647
7648 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7649 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007650 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007651}
7652
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007653/**
7654 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7655 *
7656 * @param[in] data Data node where the path is used
7657 * @param[in] path Instance-identifier node value.
7658 * @param[in,out] ret Resolved instance or NULL.
7659 *
7660 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7661 */
7662static int
7663resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7664{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007665 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007666 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007667 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007668 struct lyd_node *root, *node;
Radek Krejcidaa547a2017-09-22 15:56:27 +02007669 const char *model = NULL, *name;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007670 char *str;
7671 int mod_len, name_len, has_predicate;
7672 struct unres_data node_match;
7673
7674 memset(&node_match, 0, sizeof node_match);
7675 *ret = NULL;
7676
7677 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007678 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007679 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007680 if (root->prev) {
7681 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007682 }
7683
7684 /* search for the instance node */
7685 while (path[i]) {
7686 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7687 if (j <= 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007688 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007689 goto error;
7690 }
7691 i += j;
7692
Michal Vasko1b6ca962017-08-03 14:23:09 +02007693 if (model) {
7694 str = strndup(model, mod_len);
7695 if (!str) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007696 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007697 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007698 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02007699 mod = ly_ctx_get_module(ctx, str, NULL, 1);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007700 if (ctx->data_clb) {
7701 if (!mod) {
7702 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7703 } else if (!mod->implemented) {
7704 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7705 }
7706 }
7707 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007708
Michal Vasko1b6ca962017-08-03 14:23:09 +02007709 if (!mod || !mod->implemented || mod->disabled) {
7710 break;
7711 }
7712 } else if (!prev_mod) {
7713 /* first iteration and we are missing module name */
Michal Vaskoaf8ec362018-03-28 09:08:09 +02007714 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
7715 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
Michal Vasko1b6ca962017-08-03 14:23:09 +02007716 goto error;
7717 } else {
7718 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007719 }
7720
Radek Krejci2c822ed2017-08-03 14:23:36 +02007721 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007722 /* no instance exists */
7723 break;
7724 }
7725
7726 if (has_predicate) {
7727 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcidaa547a2017-09-22 15:56:27 +02007728 parsed = j = 0;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007729 /* index of the current node (for lists with position predicates) */
7730 cur_idx = 1;
7731 while (j < (signed)node_match.count) {
7732 node = node_match.node[j];
7733 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7734 if (parsed < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007735 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007736 goto error;
7737 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007738
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007739 if (!node) {
7740 /* current node does not satisfy the predicate */
7741 unres_data_del(&node_match, j);
7742 } else {
7743 ++j;
7744 }
7745 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007746 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007747
7748 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007749 } else if (node_match.count) {
7750 /* check that we are not addressing lists */
7751 for (j = 0; (unsigned)j < node_match.count; ++j) {
7752 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7753 unres_data_del(&node_match, j--);
7754 }
7755 }
7756 if (!node_match.count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007757 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007758 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007759 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007760
7761 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007762 }
7763
7764 if (!node_match.count) {
7765 /* no instance exists */
7766 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007767 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007768 return EXIT_FAILURE;
7769 }
7770 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7771 return EXIT_SUCCESS;
7772 } else if (node_match.count > 1) {
7773 /* instance identifier must resolve to a single node */
Michal Vasko53b7da02018-02-13 15:28:42 +01007774 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007775 goto error;
7776 } else {
7777 /* we have required result, remember it and cleanup */
7778 *ret = node_match.node[0];
7779 free(node_match.node);
7780 return EXIT_SUCCESS;
7781 }
7782
7783error:
7784 /* cleanup */
7785 free(node_match.node);
7786 return -1;
7787}
7788
7789static int
7790resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007791{
Michal Vaskoca16cb32017-07-10 11:50:33 +02007792 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007793 uint32_t i;
7794
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007795 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007796
Michal Vaskoca16cb32017-07-10 11:50:33 +02007797 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007798 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vaskoca16cb32017-07-10 11:50:33 +02007799 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007800 return -1;
7801 }
7802
Michal Vaskoca16cb32017-07-10 11:50:33 +02007803 for (i = 0; i < set->number; ++i) {
7804 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7805 continue;
7806 }
7807
Radek Krejci1899d6a2016-11-03 13:48:07 +01007808 /* not that the value is already in canonical form since the parsers does the conversion,
7809 * so we can simply compare just the values */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007810 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)set->set.d[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007811 /* we have the match */
Michal Vaskoca16cb32017-07-10 11:50:33 +02007812 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007813 break;
7814 }
7815 }
7816
Michal Vaskoca16cb32017-07-10 11:50:33 +02007817 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007818
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007819 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007820 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007821 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007822 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007823 return EXIT_FAILURE;
7824 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007825 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 +02007826 }
7827 }
7828
7829 return EXIT_SUCCESS;
7830}
7831
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007832/* 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 +01007833int
7834resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7835 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007836{
Michal Vasko53b7da02018-02-13 15:28:42 +01007837 struct ly_ctx *ctx = leaf->schema->module->ctx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007838 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007839 struct lyd_node *ret;
Michal Vasko53b7da02018-02-13 15:28:42 +01007840 enum int_log_opts prev_ilo;
7841 int found, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007842 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007843
7844 assert(type->base == LY_TYPE_UNION);
7845
Michal Vasko70bf8e52018-03-26 11:32:33 +02007846 if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LYTYPE_UNRES))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007847 /* either NULL or instid previously converted to JSON */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007848 json_val = lydict_insert(ctx, leaf->value.string, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007849 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007850
Michal Vaskofd6c6502017-01-06 12:15:41 +01007851 if (store) {
Michal Vasko70bf8e52018-03-26 11:32:33 +02007852 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007853 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007854 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007855
7856 /* 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 +01007857 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007858
7859 t = NULL;
7860 found = 0;
7861 while ((t = lyp_get_next_union_type(type, t, &found))) {
7862 found = 0;
7863
7864 switch (t->base) {
7865 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007866 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7867 req_inst = -1;
7868 } else {
7869 req_inst = t->info.lref.req;
7870 }
7871
7872 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007873 if (store) {
7874 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7875 /* valid resolved */
7876 leaf->value.leafref = ret;
7877 leaf->value_type = LY_TYPE_LEAFREF;
7878 } else {
7879 /* valid unresolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01007880 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko31a2d322018-01-12 13:36:12 +01007881 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007882 return -1;
7883 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007884 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007885 }
7886 }
7887
7888 success = 1;
7889 }
7890 break;
7891 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007892 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7893 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7894 req_inst = -1;
7895 } else {
7896 req_inst = t->info.inst.req;
7897 }
7898
Michal Vaskod3a03112017-01-23 09:56:02 +01007899 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007900 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007901 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007902 /* valid resolved */
7903 leaf->value.instance = ret;
7904 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007905
Michal Vaskofd6c6502017-01-06 12:15:41 +01007906 if (json_val) {
7907 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7908 leaf->value_str = json_val;
7909 json_val = NULL;
7910 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007911 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007912 /* valid unresolved */
7913 if (json_val) {
7914 /* put the JSON val back */
7915 leaf->value.string = json_val;
7916 json_val = NULL;
7917 } else {
7918 leaf->value.instance = NULL;
7919 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02007920 leaf->value_type = LY_TYPE_INST;
7921 leaf->value_flags |= LYTYPE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007922 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007923 }
7924
7925 success = 1;
7926 }
7927 break;
7928 default:
Michal Vasko31a2d322018-01-12 13:36:12 +01007929 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007930 success = 1;
7931 }
7932 break;
7933 }
7934
7935 if (success) {
7936 break;
7937 }
7938
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007939 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007940 if (store) {
Michal Vasko70bf8e52018-03-26 11:32:33 +02007941 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007942 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007943 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007944 }
7945
7946 /* turn logging back on */
Michal Vasko53b7da02018-02-13 15:28:42 +01007947 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007948
7949 if (json_val) {
7950 if (!success) {
7951 /* put the value back for now */
7952 assert(leaf->value_type == LY_TYPE_UNION);
7953 leaf->value.string = json_val;
7954 } else {
7955 /* value was ultimately useless, but we could not have known */
7956 lydict_remove(leaf->schema->module->ctx, json_val);
7957 }
7958 }
7959
Michal Vaskofd6c6502017-01-06 12:15:41 +01007960 if (success) {
7961 if (resolved_type) {
7962 *resolved_type = t;
7963 }
7964 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007965 /* not found and it is required */
Michal Vasko53b7da02018-02-13 15:28:42 +01007966 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007967 return EXIT_FAILURE;
7968 }
7969
7970 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007971
Radek Krejci9b6aad22016-09-20 15:55:51 +02007972}
7973
Michal Vasko8bcdf292015-08-19 14:04:43 +02007974/**
7975 * @brief Resolve a single unres data item. Logs directly.
7976 *
Michal Vaskocf024702015-10-08 15:01:42 +02007977 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007978 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007979 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007980 *
7981 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7982 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007983int
Michal Vasko0b963112017-08-11 12:45:36 +02007984resolve_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 +02007985{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007986 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007987 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007988 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007989 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007990
Michal Vasko83a6c462015-10-08 16:43:53 +02007991 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007992 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007993
Michal Vaskocf024702015-10-08 15:01:42 +02007994 switch (type) {
7995 case UNRES_LEAFREF:
7996 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007997 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007998 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7999 req_inst = -1;
8000 } else {
8001 req_inst = sleaf->type.info.lref.req;
8002 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008003 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
8004 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01008005 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008006 /* valid resolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02008007 if (leaf->value_type == LY_TYPE_BITS) {
Michal Vasko1c8567a2017-01-05 13:42:27 +01008008 free(leaf->value.bit);
8009 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008010 leaf->value.leafref = ret;
8011 leaf->value_type = LY_TYPE_LEAFREF;
Michal Vasko70bf8e52018-03-26 11:32:33 +02008012 leaf->value_flags &= ~LYTYPE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008013 } else {
8014 /* valid unresolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02008015 if (!(leaf->value_flags & LYTYPE_UNRES)) {
Michal Vasko31a2d322018-01-12 13:36:12 +01008016 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008017 return -1;
8018 }
8019 }
8020 }
8021 leaf->validity &= ~LYD_VAL_LEAFREF;
8022 } else {
8023 return rc;
8024 }
8025 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008026
Michal Vaskocf024702015-10-08 15:01:42 +02008027 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02008028 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01008029 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
8030 if (ext_dep == -1) {
8031 return -1;
8032 }
8033
8034 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
8035 req_inst = -1;
8036 } else {
8037 req_inst = sleaf->type.info.inst.req;
8038 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008039 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
8040 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008041 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008042 /* valid resolved */
8043 leaf->value.instance = ret;
8044 leaf->value_type = LY_TYPE_INST;
Michal Vasko70bf8e52018-03-26 11:32:33 +02008045 leaf->value_flags &= ~LYTYPE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008046 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008047 /* valid unresolved */
8048 leaf->value.instance = NULL;
Michal Vasko70bf8e52018-03-26 11:32:33 +02008049 leaf->value_type = LY_TYPE_INST;
8050 leaf->value_flags |= LYTYPE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008051 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008052 } else {
8053 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008054 }
Michal Vaskocf024702015-10-08 15:01:42 +02008055 break;
8056
Radek Krejci7de36cf2016-09-12 16:18:50 +02008057 case UNRES_UNION:
8058 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008059 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02008060
Michal Vaskocf024702015-10-08 15:01:42 +02008061 case UNRES_WHEN:
Michal Vasko0b963112017-08-11 12:45:36 +02008062 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02008063 return rc;
8064 }
8065 break;
8066
Michal Vaskobf19d252015-10-08 15:39:17 +02008067 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008068 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02008069 return rc;
8070 }
8071 break;
8072
8073 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008074 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02008075 return rc;
8076 }
8077 break;
8078
Michal Vaskocf024702015-10-08 15:01:42 +02008079 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01008080 LOGINT(NULL);
Michal Vasko8bcdf292015-08-19 14:04:43 +02008081 return -1;
8082 }
8083
8084 return EXIT_SUCCESS;
8085}
8086
8087/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01008088 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02008089 *
8090 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02008091 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008092 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01008093 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008094 */
8095int
Radek Krejci0b7704f2016-03-18 12:16:14 +01008096unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02008097{
Radek Krejci03b71f72016-03-16 11:10:09 +01008098 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02008099 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02008100 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02008101
Radek Krejci03b71f72016-03-16 11:10:09 +01008102 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01008103 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01008104 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008105 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01008106 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01008107 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008108 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008109
Radek Krejci0b7704f2016-03-18 12:16:14 +01008110 if (type == UNRES_WHEN) {
8111 /* remove previous result */
8112 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008113 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008114
Michal Vasko53b7da02018-02-13 15:28:42 +01008115 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008116}
8117
8118/**
8119 * @brief Resolve every unres data item in the structure. Logs directly.
8120 *
Michal Vasko660582a2018-03-19 10:10:08 +01008121 * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
8122 * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
8123 * non-presence containers may need to be deleted).
Radek Krejci082c84f2016-10-17 16:33:06 +02008124 *
8125 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
8126 *
Michal Vasko53b7da02018-02-13 15:28:42 +01008127 * @param[in] ctx Context used.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008128 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02008129 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
8130 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008131 *
8132 * @return EXIT_SUCCESS on success, -1 on error.
8133 */
8134int
Michal Vasko53b7da02018-02-13 15:28:42 +01008135resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008136{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008137 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008138 int rc, progress, ignore_fail;
Michal Vasko53b7da02018-02-13 15:28:42 +01008139 enum int_log_opts prev_ilo;
8140 struct ly_err_item *prev_eitem;
mohitarora2489837dc2018-05-01 15:09:36 +05308141 LY_ERR prev_ly_errno = ly_errno;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008142 struct lyd_node *parent;
Michal Vasko0b963112017-08-11 12:45:36 +02008143 struct lys_when *when;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008144
Radek Krejci082c84f2016-10-17 16:33:06 +02008145 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01008146 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01008147
8148 if (!unres->count) {
8149 return EXIT_SUCCESS;
8150 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008151
Michal Vasko7fa93142018-03-19 09:59:10 +01008152 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008153 ignore_fail = 1;
8154 } else if (options & LYD_OPT_NOEXTDEPS) {
8155 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008156 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008157 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008158 }
8159
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008160 LOGVRB("Resolving unresolved data nodes and their constraints...");
Michal Vasko7fa93142018-03-19 09:59:10 +01008161 if (!ignore_fail) {
8162 /* remember logging state only if errors are generated and valid */
Michal Vasko7fa93142018-03-19 09:59:10 +01008163 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8164 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008165
Michal Vasko7fa93142018-03-19 09:59:10 +01008166 /*
8167 * when-stmt first
8168 */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008169 first = 1;
8170 stmt_count = 0;
8171 resolved = 0;
8172 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01008173 do {
Michal Vasko7fa93142018-03-19 09:59:10 +01008174 if (!ignore_fail) {
8175 ly_err_free_next(ctx, prev_eitem);
8176 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008177 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02008178 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008179 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008180 continue;
8181 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008182 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008183 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008184 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008185 }
8186
8187 /* resolve when condition only when all parent when conditions are already resolved */
8188 for (parent = unres->node[i]->parent;
8189 parent && LYD_WHEN_DONE(parent->when_status);
8190 parent = parent->parent) {
8191 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8192 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02008193 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01008194 */
8195 unres->node[i]->when_status |= LYD_WHEN_FALSE;
8196 unres->type[i] = UNRES_RESOLVED;
8197 resolved++;
8198 break;
8199 }
8200 }
8201 if (parent) {
8202 continue;
8203 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008204
Michal Vasko0b963112017-08-11 12:45:36 +02008205 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01008206 if (!rc) {
Michal Vasko0b963112017-08-11 12:45:36 +02008207 /* finish with error/delete the node only if when was false, an external dependency was not required,
8208 * or it was not provided (the flag would not be passed down otherwise, checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02008209 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vaskoc04173b2018-03-09 10:43:22 +01008210 && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
Radek Krejci082c84f2016-10-17 16:33:06 +02008211 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01008212 /* false when condition */
Michal Vasko53b7da02018-02-13 15:28:42 +01008213 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008214 } /* follows else */
8215
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008216 /* auto-delete */
Michal Vasko53b7da02018-02-13 15:28:42 +01008217 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008218
Radek Krejci0c0086a2016-03-24 15:20:28 +01008219 /* only unlink now, the subtree can contain another nodes stored in the unres list */
8220 /* if it has parent non-presence containers that would be empty, we should actually
8221 * remove the container
8222 */
Radek Krejci2537fd32016-09-07 16:22:41 +02008223 for (parent = unres->node[i];
8224 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8225 parent = parent->parent) {
8226 if (((struct lys_node_container *)parent->parent->schema)->presence) {
8227 /* presence container */
8228 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008229 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008230 if (parent->next || parent->prev != parent) {
8231 /* non empty (the child we are in and we are going to remove is not the only child) */
8232 break;
8233 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008234 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008235 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008236
Radek Krejci0c0086a2016-03-24 15:20:28 +01008237 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008238 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01008239 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008240
Radek Krejci0b7704f2016-03-18 12:16:14 +01008241 lyd_unlink(unres->node[i]);
8242 unres->type[i] = UNRES_DELETE;
8243 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01008244
8245 /* update the rest of unres items */
8246 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01008247 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01008248 continue;
8249 }
8250
8251 /* test if the node is in subtree to be deleted */
8252 for (parent = unres->node[j]; parent; parent = parent->parent) {
8253 if (parent == unres->node[i]) {
8254 /* yes, it is */
8255 unres->type[j] = UNRES_RESOLVED;
8256 resolved++;
8257 break;
8258 }
8259 }
8260 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008261 } else {
8262 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01008263 }
Michal Vasko7fa93142018-03-19 09:59:10 +01008264 if (!ignore_fail) {
8265 ly_err_free_next(ctx, prev_eitem);
8266 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008267 resolved++;
8268 progress = 1;
8269 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008270 goto error;
Radek Krejci2467a492016-10-24 15:16:59 +02008271 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01008272 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008273 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008274 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01008275
Radek Krejci0b7704f2016-03-18 12:16:14 +01008276 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008277 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008278 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008279 }
8280
8281 for (i = 0; del_items && i < unres->count; i++) {
8282 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8283 if (unres->type[i] != UNRES_DELETE) {
8284 continue;
8285 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008286 if (!unres->node[i]) {
8287 unres->type[i] = UNRES_RESOLVED;
8288 del_items--;
8289 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008290 }
8291
8292 /* really remove the complete subtree */
8293 lyd_free(unres->node[i]);
8294 unres->type[i] = UNRES_RESOLVED;
8295 del_items--;
8296 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008297
Michal Vasko7fa93142018-03-19 09:59:10 +01008298 /*
8299 * now leafrefs
8300 */
8301 if (options & LYD_OPT_TRUSTED) {
8302 /* we want to attempt to resolve leafrefs */
8303 assert(!ignore_fail);
8304 ignore_fail = 1;
8305
8306 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8307 ly_errno = prev_ly_errno;
8308 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008309 first = 1;
8310 stmt_count = 0;
8311 resolved = 0;
8312 do {
8313 progress = 0;
8314 for (i = 0; i < unres->count; i++) {
8315 if (unres->type[i] != UNRES_LEAFREF) {
8316 continue;
8317 }
8318 if (first) {
8319 /* count leafref nodes in unres list */
8320 stmt_count++;
8321 }
8322
Michal Vasko0b963112017-08-11 12:45:36 +02008323 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008324 if (!rc) {
8325 unres->type[i] = UNRES_RESOLVED;
Michal Vasko7fa93142018-03-19 09:59:10 +01008326 if (!ignore_fail) {
8327 ly_err_free_next(ctx, prev_eitem);
8328 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008329 resolved++;
8330 progress = 1;
8331 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008332 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008333 } /* else forward reference */
8334 }
8335 first = 0;
8336 } while (progress && resolved < stmt_count);
8337
8338 /* do we have some unresolved leafrefs? */
8339 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008340 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008341 }
8342
Michal Vasko7fa93142018-03-19 09:59:10 +01008343 if (!ignore_fail) {
8344 /* log normally now, throw away irrelevant errors */
8345 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8346 ly_errno = prev_ly_errno;
8347 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008348
Michal Vasko7fa93142018-03-19 09:59:10 +01008349 /*
8350 * rest
8351 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008352 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008353 if (unres->type[i] == UNRES_RESOLVED) {
8354 continue;
8355 }
Radek Krejci082c84f2016-10-17 16:33:06 +02008356 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01008357
Michal Vasko0b963112017-08-11 12:45:36 +02008358 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008359 if (rc) {
8360 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008361 return -1;
8362 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008363
8364 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008365 }
8366
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008367 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01008368 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008369 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01008370
8371error:
Michal Vasko7fa93142018-03-19 09:59:10 +01008372 if (!ignore_fail) {
8373 /* print all the new errors */
8374 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8375 /* do not restore ly_errno, it was udpated properly */
8376 }
Michal Vasko53b7da02018-02-13 15:28:42 +01008377 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02008378}