blob: f68262f432ea075092f225f8f009f05d6b20d5e1 [file] [log] [blame]
Michal Vasko730dfdf2015-08-11 14:48:05 +02001/**
2 * @file resolve.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libyang resolve functions
5 *
Michal Vasko53b7da02018-02-13 15:28:42 +01006 * Copyright (c) 2015 - 2018 CESNET, z.s.p.o.
Michal Vasko730dfdf2015-08-11 14:48:05 +02007 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Michal Vasko6c810702018-03-14 16:23:21 +010030#include "hash_table.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
Radek Krejcie534c132016-11-23 13:32:31 +010032#include "extensions.h"
Michal Vasko185b5272018-09-13 14:26:12 +020033#include "validation.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020034
Michal Vasko2d44ee02018-05-18 09:38:51 +020035/* internal parsed predicate structure */
36struct parsed_pred {
37 const struct lys_node *schema;
38 int len;
39 struct {
40 const char *mod_name;
41 int mod_name_len;
42 const char *name;
43 int nam_len;
44 const char *value;
45 int val_len;
46 } *pred;
47};
48
Michal Vaskod24dd012016-09-30 12:20:22 +020049int
50parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020051{
52 const char *ptr;
53 int minus = 0;
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020054 int64_t ret = 0, prev_ret;
Radek Krejcibf47a822016-11-04 10:06:08 +010055 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020056
57 ptr = *str_num;
58
59 if (ptr[0] == '-') {
60 minus = 1;
61 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010062 } else if (ptr[0] == '+') {
63 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020064 }
65
Michal Vaskod24dd012016-09-30 12:20:22 +020066 if (!isdigit(ptr[0])) {
67 /* there must be at least one */
68 return 1;
69 }
70
Michal Vasko4d1f0482016-09-19 14:35:06 +020071 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
72 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020073 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020074 }
75
76 if (ptr[0] == '.') {
77 if (ptr[1] == '.') {
78 /* it's the next interval */
79 break;
80 }
81 ++str_dig;
82 } else {
Michal Vaskoe2ea45a2017-08-07 13:15:07 +020083 prev_ret = ret;
84 if (minus) {
85 ret = ret * 10 - (ptr[0] - '0');
86 if (ret > prev_ret) {
87 return 1;
88 }
89 } else {
90 ret = ret * 10 + (ptr[0] - '0');
91 if (ret < prev_ret) {
92 return 1;
93 }
94 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020095 if (str_dig > -1) {
96 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010097 if (ptr[0] == '0') {
98 /* possibly trailing zero */
99 trailing_zeros++;
100 } else {
101 trailing_zeros = 0;
102 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200103 }
104 ++str_exp;
105 }
106 }
Michal Vaskod24dd012016-09-30 12:20:22 +0200107 if (str_dig == 0) {
108 /* no digits after '.' */
109 return 1;
110 } else if (str_dig == -1) {
111 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +0200112 str_dig = 0;
113 }
Radek Krejcibf47a822016-11-04 10:06:08 +0100114 /* remove trailing zeros */
115 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +0100116 str_dig -= trailing_zeros;
117 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +0100118 ret = ret / dec_pow(trailing_zeros);
119 }
Michal Vasko4d1f0482016-09-19 14:35:06 +0200120
121 /* it's parsed, now adjust the number based on fraction-digits, if needed */
122 if (str_dig < dig) {
123 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200124 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200125 }
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200126 prev_ret = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200127 ret *= dec_pow(dig - str_dig);
Michal Vaskoe2ea45a2017-08-07 13:15:07 +0200128 if ((minus && (ret > prev_ret)) || (!minus && (ret < prev_ret))) {
129 return 1;
130 }
131
Michal Vasko4d1f0482016-09-19 14:35:06 +0200132 }
133 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200134 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200135 }
136
Michal Vasko4d1f0482016-09-19 14:35:06 +0200137 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200138 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200139
Michal Vaskod24dd012016-09-30 12:20:22 +0200140 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200141}
142
143/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200144 * @brief Parse an identifier.
145 *
146 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
147 * identifier = (ALPHA / "_")
148 * *(ALPHA / DIGIT / "_" / "-" / ".")
149 *
Michal Vaskobb211122015-08-19 14:03:11 +0200150 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200151 *
152 * @return Number of characters successfully parsed.
153 */
Radek Krejcidce5f972017-09-12 15:47:49 +0200154unsigned int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200155parse_identifier(const char *id)
156{
Radek Krejcidce5f972017-09-12 15:47:49 +0200157 unsigned int parsed = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200158
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100159 assert(id);
160
Radek Krejci6dc53a22015-08-17 13:27:59 +0200161 if (!isalpha(id[0]) && (id[0] != '_')) {
162 return -parsed;
163 }
164
165 ++parsed;
166 ++id;
167
168 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
169 ++parsed;
170 ++id;
171 }
172
173 return parsed;
174}
175
176/**
177 * @brief Parse a node-identifier.
178 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200179 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200180 *
Michal Vaskobb211122015-08-19 14:03:11 +0200181 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200182 * @param[out] mod_name Points to the module name, NULL if there is not any.
183 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200184 * @param[out] name Points to the node name.
185 * @param[out] nam_len Length of the node name.
Michal Vasko50576712017-07-28 12:28:33 +0200186 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
PavolVicanb28bbff2018-02-21 00:44:02 +0100187 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:]., prefix:#identifier).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200188 *
189 * @return Number of characters successfully parsed,
190 * positive on success, negative on failure.
191 */
192static int
Michal Vasko50576712017-07-28 12:28:33 +0200193parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
194 int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200195{
PavolVican195cf392018-02-23 13:24:45 +0100196 int parsed = 0, ret, all_desc_local = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200197
198 assert(id);
Michal Vasko50576712017-07-28 12:28:33 +0200199 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
200 assert((name && nam_len) || (!name && !nam_len));
Michal Vasko50576712017-07-28 12:28:33 +0200201
Michal Vasko723e50c2015-10-20 15:20:29 +0200202 if (mod_name) {
203 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200204 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200205 }
206 if (name) {
207 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200208 *nam_len = 0;
209 }
210
Michal Vasko50576712017-07-28 12:28:33 +0200211 if (extended) {
212 /* try to parse only the extended expressions */
213 if (id[parsed] == '/') {
PavolVican195cf392018-02-23 13:24:45 +0100214 if (all_desc) {
215 *all_desc = 1;
216 }
217 all_desc_local = 1;
Michal Vasko50576712017-07-28 12:28:33 +0200218 } else {
PavolVican195cf392018-02-23 13:24:45 +0100219 if (all_desc) {
220 *all_desc = 0;
221 }
Michal Vasko50576712017-07-28 12:28:33 +0200222 }
223
224 /* is there a prefix? */
PavolVican195cf392018-02-23 13:24:45 +0100225 ret = parse_identifier(id + all_desc_local);
Michal Vasko50576712017-07-28 12:28:33 +0200226 if (ret > 0) {
PavolVican195cf392018-02-23 13:24:45 +0100227 if (id[all_desc_local + ret] != ':') {
Michal Vasko50576712017-07-28 12:28:33 +0200228 /* this is not a prefix, so not an extended id */
229 goto standard_id;
230 }
231
232 if (mod_name) {
PavolVican195cf392018-02-23 13:24:45 +0100233 *mod_name = id + all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200234 *mod_name_len = ret;
235 }
236
237 /* "/" and ":" */
PavolVican195cf392018-02-23 13:24:45 +0100238 ret += all_desc_local + 1;
Michal Vasko50576712017-07-28 12:28:33 +0200239 } else {
PavolVican195cf392018-02-23 13:24:45 +0100240 ret = all_desc_local;
Michal Vasko50576712017-07-28 12:28:33 +0200241 }
242
243 /* parse either "*" or "." */
PavolVicanb28bbff2018-02-21 00:44:02 +0100244 if (*(id + ret) == '*') {
Michal Vasko50576712017-07-28 12:28:33 +0200245 if (name) {
246 *name = id + ret;
247 *nam_len = 1;
248 }
249 ++ret;
250
251 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100252 } else if (*(id + ret) == '.') {
PavolVican195cf392018-02-23 13:24:45 +0100253 if (!all_desc_local) {
Michal Vasko50576712017-07-28 12:28:33 +0200254 /* /. is redundant expression, we do not accept it */
255 return -ret;
256 }
257
258 if (name) {
259 *name = id + ret;
260 *nam_len = 1;
261 }
262 ++ret;
263
264 return ret;
PavolVicanb28bbff2018-02-21 00:44:02 +0100265 } else if (*(id + ret) == '#') {
PavolVican195cf392018-02-23 13:24:45 +0100266 if (all_desc_local || !ret) {
PavolVicanb28bbff2018-02-21 00:44:02 +0100267 /* no prefix */
268 return 0;
269 }
270 parsed = ret + 1;
271 if ((ret = parse_identifier(id + parsed)) < 1) {
272 return -parsed + ret;
273 }
274 *name = id + parsed - 1;
275 *nam_len = ret + 1;
276 return parsed + ret;
Michal Vasko50576712017-07-28 12:28:33 +0200277 }
278 /* else a standard id, parse it all again */
279 }
280
281standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200282 if ((ret = parse_identifier(id)) < 1) {
283 return ret;
284 }
285
Michal Vasko723e50c2015-10-20 15:20:29 +0200286 if (mod_name) {
287 *mod_name = id;
Michal Vasko723e50c2015-10-20 15:20:29 +0200288 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200289 }
290
291 parsed += ret;
292 id += ret;
293
294 /* there is prefix */
295 if (id[0] == ':') {
296 ++parsed;
297 ++id;
298
299 /* there isn't */
300 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200301 if (name && mod_name) {
302 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200303 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200304 if (mod_name) {
305 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200306 }
307
Michal Vasko723e50c2015-10-20 15:20:29 +0200308 if (nam_len && mod_name_len) {
309 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200310 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200311 if (mod_name_len) {
312 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200313 }
314
315 return parsed;
316 }
317
318 /* identifier (node name) */
319 if ((ret = parse_identifier(id)) < 1) {
320 return -parsed+ret;
321 }
322
323 if (name) {
324 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200325 *nam_len = ret;
326 }
327
328 return parsed+ret;
329}
330
331/**
332 * @brief Parse a path-predicate (leafref).
333 *
334 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
335 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
336 *
Michal Vaskobb211122015-08-19 14:03:11 +0200337 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200338 * @param[out] prefix Points to the prefix, NULL if there is not any.
339 * @param[out] pref_len Length of the prefix, 0 if there is not any.
340 * @param[out] name Points to the node name.
341 * @param[out] nam_len Length of the node name.
342 * @param[out] path_key_expr Points to the path-key-expr.
343 * @param[out] pke_len Length of the path-key-expr.
344 * @param[out] has_predicate Flag to mark whether there is another predicate following.
345 *
346 * @return Number of characters successfully parsed,
347 * positive on success, negative on failure.
348 */
349static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200350parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
351 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200352{
353 const char *ptr;
354 int parsed = 0, ret;
355
356 assert(id);
357 if (prefix) {
358 *prefix = NULL;
359 }
360 if (pref_len) {
361 *pref_len = 0;
362 }
363 if (name) {
364 *name = NULL;
365 }
366 if (nam_len) {
367 *nam_len = 0;
368 }
369 if (path_key_expr) {
370 *path_key_expr = NULL;
371 }
372 if (pke_len) {
373 *pke_len = 0;
374 }
375 if (has_predicate) {
376 *has_predicate = 0;
377 }
378
379 if (id[0] != '[') {
380 return -parsed;
381 }
382
383 ++parsed;
384 ++id;
385
386 while (isspace(id[0])) {
387 ++parsed;
388 ++id;
389 }
390
Michal Vasko50576712017-07-28 12:28:33 +0200391 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200392 return -parsed+ret;
393 }
394
395 parsed += ret;
396 id += ret;
397
398 while (isspace(id[0])) {
399 ++parsed;
400 ++id;
401 }
402
403 if (id[0] != '=') {
404 return -parsed;
405 }
406
407 ++parsed;
408 ++id;
409
410 while (isspace(id[0])) {
411 ++parsed;
412 ++id;
413 }
414
415 if ((ptr = strchr(id, ']')) == NULL) {
416 return -parsed;
417 }
418
419 --ptr;
420 while (isspace(ptr[0])) {
421 --ptr;
422 }
423 ++ptr;
424
425 ret = ptr-id;
426 if (path_key_expr) {
427 *path_key_expr = id;
428 }
429 if (pke_len) {
430 *pke_len = ret;
431 }
432
433 parsed += ret;
434 id += ret;
435
436 while (isspace(id[0])) {
437 ++parsed;
438 ++id;
439 }
440
441 assert(id[0] == ']');
442
443 if (id[1] == '[') {
444 *has_predicate = 1;
445 }
446
447 return parsed+1;
448}
449
450/**
451 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
452 * the ".." and the first node-identifier, other calls parse a single
453 * node-identifier each.
454 *
455 * path-key-expr = current-function-invocation *WSP "/" *WSP
456 * rel-path-keyexpr
457 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
458 * *(node-identifier *WSP "/" *WSP)
459 * node-identifier
460 *
Michal Vaskobb211122015-08-19 14:03:11 +0200461 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200462 * @param[out] prefix Points to the prefix, NULL if there is not any.
463 * @param[out] pref_len Length of the prefix, 0 if there is not any.
464 * @param[out] name Points to the node name.
465 * @param[out] nam_len Length of the node name.
466 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
467 * must not be changed between consecutive calls.
468 * @return Number of characters successfully parsed,
469 * positive on success, negative on failure.
470 */
471static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200472parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
473 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200474{
475 int parsed = 0, ret, par_times = 0;
476
477 assert(id);
478 assert(parent_times);
479 if (prefix) {
480 *prefix = NULL;
481 }
482 if (pref_len) {
483 *pref_len = 0;
484 }
485 if (name) {
486 *name = NULL;
487 }
488 if (nam_len) {
489 *nam_len = 0;
490 }
491
492 if (!*parent_times) {
493 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
494 if (strncmp(id, "current()", 9)) {
495 return -parsed;
496 }
497
498 parsed += 9;
499 id += 9;
500
501 while (isspace(id[0])) {
502 ++parsed;
503 ++id;
504 }
505
506 if (id[0] != '/') {
507 return -parsed;
508 }
509
510 ++parsed;
511 ++id;
512
513 while (isspace(id[0])) {
514 ++parsed;
515 ++id;
516 }
517
518 /* rel-path-keyexpr */
519 if (strncmp(id, "..", 2)) {
520 return -parsed;
521 }
522 ++par_times;
523
524 parsed += 2;
525 id += 2;
526
527 while (isspace(id[0])) {
528 ++parsed;
529 ++id;
530 }
531 }
532
533 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
534 *
535 * first parent reference with whitespaces already parsed
536 */
537 if (id[0] != '/') {
538 return -parsed;
539 }
540
541 ++parsed;
542 ++id;
543
544 while (isspace(id[0])) {
545 ++parsed;
546 ++id;
547 }
548
549 while (!strncmp(id, "..", 2) && !*parent_times) {
550 ++par_times;
551
552 parsed += 2;
553 id += 2;
554
555 while (isspace(id[0])) {
556 ++parsed;
557 ++id;
558 }
559
560 if (id[0] != '/') {
561 return -parsed;
562 }
563
564 ++parsed;
565 ++id;
566
567 while (isspace(id[0])) {
568 ++parsed;
569 ++id;
570 }
571 }
572
573 if (!*parent_times) {
574 *parent_times = par_times;
575 }
576
577 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200578 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
579 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200580 }
581
582 parsed += ret;
583 id += ret;
584
585 return parsed;
586}
587
588/**
589 * @brief Parse path-arg (leafref).
590 *
591 * path-arg = absolute-path / relative-path
592 * absolute-path = 1*("/" (node-identifier *path-predicate))
593 * relative-path = 1*(".." "/") descendant-path
594 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200595 * @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 +0200596 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200597 * @param[out] prefix Points to the prefix, NULL if there is not any.
598 * @param[out] pref_len Length of the prefix, 0 if there is not any.
599 * @param[out] name Points to the node name.
600 * @param[out] nam_len Length of the node name.
601 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
602 * must not be changed between consecutive calls. -1 if the
603 * path is relative.
604 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
605 *
606 * @return Number of characters successfully parsed,
607 * positive on success, negative on failure.
608 */
609static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200610parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200611 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612{
613 int parsed = 0, ret, par_times = 0;
614
615 assert(id);
616 assert(parent_times);
617 if (prefix) {
618 *prefix = NULL;
619 }
620 if (pref_len) {
621 *pref_len = 0;
622 }
623 if (name) {
624 *name = NULL;
625 }
626 if (nam_len) {
627 *nam_len = 0;
628 }
629 if (has_predicate) {
630 *has_predicate = 0;
631 }
632
633 if (!*parent_times && !strncmp(id, "..", 2)) {
634 ++par_times;
635
636 parsed += 2;
637 id += 2;
638
639 while (!strncmp(id, "/..", 3)) {
640 ++par_times;
641
642 parsed += 3;
643 id += 3;
644 }
645 }
646
647 if (!*parent_times) {
648 if (par_times) {
649 *parent_times = par_times;
650 } else {
651 *parent_times = -1;
652 }
653 }
654
655 if (id[0] != '/') {
656 return -parsed;
657 }
658
659 /* skip '/' */
660 ++parsed;
661 ++id;
662
663 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200664 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
665 return -parsed - ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200666 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200667 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200668 /* actually we always need prefix even it is not specified */
669 *prefix = lys_main_module(mod)->name;
670 *pref_len = strlen(*prefix);
671 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200672
673 parsed += ret;
674 id += ret;
675
676 /* there is no predicate */
677 if ((id[0] == '/') || !id[0]) {
678 return parsed;
679 } else if (id[0] != '[') {
680 return -parsed;
681 }
682
683 if (has_predicate) {
684 *has_predicate = 1;
685 }
686
687 return parsed;
688}
689
690/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200691 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200692 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200693 *
694 * instance-identifier = 1*("/" (node-identifier *predicate))
695 *
Michal Vaskobb211122015-08-19 14:03:11 +0200696 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200697 * @param[out] model Points to the model name.
698 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200699 * @param[out] name Points to the node name.
700 * @param[out] nam_len Length of the node name.
701 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
702 *
703 * @return Number of characters successfully parsed,
704 * positive on success, negative on failure.
705 */
706static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200707parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
708 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200709{
710 int parsed = 0, ret;
711
Michal Vasko1b6ca962017-08-03 14:23:09 +0200712 assert(id && model && mod_len && name && nam_len);
713
Radek Krejci6dc53a22015-08-17 13:27:59 +0200714 if (has_predicate) {
715 *has_predicate = 0;
716 }
717
718 if (id[0] != '/') {
719 return -parsed;
720 }
721
722 ++parsed;
723 ++id;
724
Michal Vaskob2f40be2016-09-08 16:03:48 +0200725 if ((ret = parse_identifier(id)) < 1) {
726 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200727 }
728
Michal Vaskob2f40be2016-09-08 16:03:48 +0200729 *name = id;
730 *nam_len = ret;
731
732 parsed += ret;
733 id += ret;
734
Michal Vasko1b6ca962017-08-03 14:23:09 +0200735 if (id[0] == ':') {
736 /* we have prefix */
737 *model = *name;
738 *mod_len = *nam_len;
739
740 ++parsed;
741 ++id;
742
743 if ((ret = parse_identifier(id)) < 1) {
744 return ret;
745 }
746
747 *name = id;
748 *nam_len = ret;
749
750 parsed += ret;
751 id += ret;
752 }
753
Radek Krejci4967cb62016-09-14 16:40:28 +0200754 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200755 *has_predicate = 1;
756 }
757
758 return parsed;
759}
760
761/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200762 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200763 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200764 *
765 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
766 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
767 * ((DQUOTE string DQUOTE) /
768 * (SQUOTE string SQUOTE))
769 * pos = non-negative-integer-value
770 *
Michal Vaskobb211122015-08-19 14:03:11 +0200771 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200772 * @param[out] model Points to the model name.
773 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200774 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
775 * @param[out] nam_len Length of the node name.
776 * @param[out] value Value the node-identifier must have (string from the grammar),
777 * NULL if there is not any.
778 * @param[out] val_len Length of the value, 0 if there is not any.
779 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
780 *
781 * @return Number of characters successfully parsed,
782 * positive on success, negative on failure.
783 */
784static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200785parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
786 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200787{
788 const char *ptr;
789 int parsed = 0, ret;
790 char quote;
791
792 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200793 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200794 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200795 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200796 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200797 }
798 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200799 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200800 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200801 *nam_len = 0;
802 }
803 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200804 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200805 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200806 *val_len = 0;
807 }
808 if (has_predicate) {
809 *has_predicate = 0;
810 }
811
812 if (id[0] != '[') {
813 return -parsed;
814 }
815
816 ++parsed;
817 ++id;
818
819 while (isspace(id[0])) {
820 ++parsed;
821 ++id;
822 }
823
824 /* pos */
825 if (isdigit(id[0])) {
826 if (name) {
827 *name = id;
828 }
829
830 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200831 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200832 }
833
834 while (isdigit(id[0])) {
835 ++parsed;
836 ++id;
837 }
838
839 if (nam_len) {
840 *nam_len = id-(*name);
841 }
842
Michal Vaskof2f28a12016-09-09 12:43:06 +0200843 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200844 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200845 if (id[0] == '.') {
846 if (name) {
847 *name = id;
848 }
849 if (nam_len) {
850 *nam_len = 1;
851 }
852
853 ++parsed;
854 ++id;
855
856 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200857 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200858 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200859 }
860
861 parsed += ret;
862 id += ret;
863 }
864
865 while (isspace(id[0])) {
866 ++parsed;
867 ++id;
868 }
869
870 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200871 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200872 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200873
Radek Krejci6dc53a22015-08-17 13:27:59 +0200874 ++parsed;
875 ++id;
876
Michal Vaskof2f28a12016-09-09 12:43:06 +0200877 while (isspace(id[0])) {
878 ++parsed;
879 ++id;
880 }
881
882 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
883 if ((id[0] == '\"') || (id[0] == '\'')) {
884 quote = id[0];
885
886 ++parsed;
887 ++id;
888
889 if ((ptr = strchr(id, quote)) == NULL) {
890 return -parsed;
891 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200892 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200893
894 if (value) {
895 *value = id;
896 }
897 if (val_len) {
898 *val_len = ret;
899 }
900
Michal Vasko1b6ca962017-08-03 14:23:09 +0200901 parsed += ret + 1;
902 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200903 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200904 return -parsed;
905 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200906 }
907
908 while (isspace(id[0])) {
909 ++parsed;
910 ++id;
911 }
912
913 if (id[0] != ']') {
914 return -parsed;
915 }
916
917 ++parsed;
918 ++id;
919
920 if ((id[0] == '[') && has_predicate) {
921 *has_predicate = 1;
922 }
923
924 return parsed;
925}
926
927/**
928 * @brief Parse schema-nodeid.
929 *
930 * schema-nodeid = absolute-schema-nodeid /
931 * descendant-schema-nodeid
932 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200933 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200934 * node-identifier
935 * absolute-schema-nodeid
936 *
Michal Vaskobb211122015-08-19 14:03:11 +0200937 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200938 * @param[out] mod_name Points to the module name, NULL if there is not any.
939 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200940 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200941 * @param[out] nam_len Length of the node name.
942 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
943 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100944 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
945 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200946 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200947 *
948 * @return Number of characters successfully parsed,
949 * positive on success, negative on failure.
950 */
Michal Vasko22448d32016-03-16 13:17:29 +0100951int
Michal Vasko723e50c2015-10-20 15:20:29 +0200952parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko50576712017-07-28 12:28:33 +0200953 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200954{
955 int parsed = 0, ret;
956
957 assert(id);
958 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200959
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100960 if (has_predicate) {
961 *has_predicate = 0;
962 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200963
964 if (id[0] != '/') {
965 if (*is_relative != -1) {
966 return -parsed;
967 } else {
968 *is_relative = 1;
969 }
Michal Vasko48935352016-03-29 11:52:36 +0200970 if (!strncmp(id, "./", 2)) {
971 parsed += 2;
972 id += 2;
973 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200974 } else {
975 if (*is_relative == -1) {
976 *is_relative = 0;
977 }
978 ++parsed;
979 ++id;
980 }
981
Michal Vasko50576712017-07-28 12:28:33 +0200982 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
983 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200984 }
985
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100986 parsed += ret;
987 id += ret;
988
989 if ((id[0] == '[') && has_predicate) {
990 *has_predicate = 1;
991 }
992
993 return parsed;
994}
995
996/**
997 * @brief Parse schema predicate (special format internally used).
998 *
999 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001000 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001001 * key-with-value = identifier *WSP "=" *WSP
1002 * ((DQUOTE string DQUOTE) /
1003 * (SQUOTE string SQUOTE))
1004 *
1005 * @param[in] id Identifier to use.
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001006 * @param[out] mod_name Points to the list key module name.
1007 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001008 * @param[out] name Points to the list key name.
1009 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +01001010 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001011 * @param[out] val_len Length of \p value.
1012 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
1013 */
Michal Vasko22448d32016-03-16 13:17:29 +01001014int
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001015parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
1016 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001017{
1018 const char *ptr;
1019 int parsed = 0, ret;
1020 char quote;
1021
1022 assert(id);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001023 if (mod_name) {
1024 *mod_name = NULL;
1025 }
1026 if (mod_name_len) {
1027 *mod_name_len = 0;
1028 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001029 if (name) {
1030 *name = NULL;
1031 }
1032 if (nam_len) {
1033 *nam_len = 0;
1034 }
1035 if (value) {
1036 *value = NULL;
1037 }
1038 if (val_len) {
1039 *val_len = 0;
1040 }
1041 if (has_predicate) {
1042 *has_predicate = 0;
1043 }
1044
1045 if (id[0] != '[') {
1046 return -parsed;
1047 }
1048
1049 ++parsed;
1050 ++id;
1051
1052 while (isspace(id[0])) {
1053 ++parsed;
1054 ++id;
1055 }
1056
Michal Vasko22448d32016-03-16 13:17:29 +01001057 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001058 if (id[0] == '.') {
1059 ret = 1;
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001060
1061 if (name) {
1062 *name = id;
1063 }
1064 if (nam_len) {
1065 *nam_len = ret;
1066 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001067 } else if (isdigit(id[0])) {
1068 if (id[0] == '0') {
1069 return -parsed;
1070 }
1071 ret = 1;
1072 while (isdigit(id[ret])) {
1073 ++ret;
1074 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02001075
1076 if (name) {
1077 *name = id;
1078 }
1079 if (nam_len) {
1080 *nam_len = ret;
1081 }
Michal Vasko50576712017-07-28 12:28:33 +02001082 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001083 return -parsed + ret;
1084 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001085
1086 parsed += ret;
1087 id += ret;
1088
1089 while (isspace(id[0])) {
1090 ++parsed;
1091 ++id;
1092 }
1093
1094 /* there is value as well */
1095 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001096 if (name && isdigit(**name)) {
1097 return -parsed;
1098 }
1099
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001100 ++parsed;
1101 ++id;
1102
1103 while (isspace(id[0])) {
1104 ++parsed;
1105 ++id;
1106 }
1107
1108 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1109 if ((id[0] == '\"') || (id[0] == '\'')) {
1110 quote = id[0];
1111
1112 ++parsed;
1113 ++id;
1114
1115 if ((ptr = strchr(id, quote)) == NULL) {
1116 return -parsed;
1117 }
1118 ret = ptr - id;
1119
1120 if (value) {
1121 *value = id;
1122 }
1123 if (val_len) {
1124 *val_len = ret;
1125 }
1126
1127 parsed += ret + 1;
1128 id += ret + 1;
1129 } else {
1130 return -parsed;
1131 }
1132
1133 while (isspace(id[0])) {
1134 ++parsed;
1135 ++id;
1136 }
1137 }
1138
1139 if (id[0] != ']') {
1140 return -parsed;
1141 }
1142
1143 ++parsed;
1144 ++id;
1145
1146 if ((id[0] == '[') && has_predicate) {
1147 *has_predicate = 1;
1148 }
1149
1150 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001151}
1152
Michal Vasko2d44ee02018-05-18 09:38:51 +02001153#ifdef LY_ENABLED_CACHE
1154
1155static int
1156resolve_hash_table_find_equal(void *val1_p, void *val2_p, int mod, void *UNUSED(cb_data))
1157{
1158 struct lyd_node *val2, *elem2;
1159 struct parsed_pred pp;
1160 const char *str;
1161 int i;
1162
1163 assert(!mod);
Michal Vasko87e29a82018-05-21 13:50:43 +02001164 (void)mod;
Michal Vasko2d44ee02018-05-18 09:38:51 +02001165
1166 pp = *((struct parsed_pred *)val1_p);
1167 val2 = *((struct lyd_node **)val2_p);
1168
1169 if (val2->schema != pp.schema) {
1170 return 0;
1171 }
1172
1173 switch (val2->schema->nodetype) {
1174 case LYS_CONTAINER:
1175 case LYS_LEAF:
1176 case LYS_ANYXML:
1177 case LYS_ANYDATA:
1178 return 1;
1179 case LYS_LEAFLIST:
1180 str = ((struct lyd_node_leaf_list *)val2)->value_str;
1181 if (!strncmp(str, pp.pred[0].value, pp.pred[0].val_len) && !str[pp.pred[0].val_len]) {
1182 return 1;
1183 }
1184 return 0;
1185 case LYS_LIST:
1186 assert(((struct lys_node_list *)val2->schema)->keys_size);
1187 assert(((struct lys_node_list *)val2->schema)->keys_size == pp.len);
1188
1189 /* lists with keys, their equivalence is based on their keys */
1190 elem2 = val2->child;
1191 /* the exact data order is guaranteed */
1192 for (i = 0; elem2 && (i < pp.len); ++i) {
1193 /* module check */
1194 if (pp.pred[i].mod_name) {
1195 if (strncmp(lyd_node_module(elem2)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
1196 || lyd_node_module(elem2)->name[pp.pred[i].mod_name_len]) {
1197 break;
1198 }
1199 } else {
1200 if (lyd_node_module(elem2) != lys_node_module(pp.schema)) {
1201 break;
1202 }
1203 }
1204
1205 /* name check */
1206 if (strncmp(elem2->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || elem2->schema->name[pp.pred[i].nam_len]) {
1207 break;
1208 }
1209
1210 /* value check */
1211 str = ((struct lyd_node_leaf_list *)elem2)->value_str;
1212 if (strncmp(str, pp.pred[i].value, pp.pred[i].val_len) || str[pp.pred[i].val_len]) {
1213 break;
1214 }
1215
1216 /* next key */
1217 elem2 = elem2->next;
1218 }
1219 if (i == pp.len) {
1220 return 1;
1221 }
1222 return 0;
1223 default:
1224 break;
1225 }
1226
1227 LOGINT(val2->schema->module->ctx);
1228 return 0;
1229}
1230
1231static struct lyd_node *
1232resolve_json_data_node_hash(struct lyd_node *parent, struct parsed_pred pp)
1233{
1234 values_equal_cb prev_cb;
1235 struct lyd_node **ret = NULL;
1236 uint32_t hash;
1237 int i;
1238
1239 assert(parent && parent->hash);
1240
1241 /* set our value equivalence callback that does not require data nodes */
1242 prev_cb = lyht_set_cb(parent->ht, resolve_hash_table_find_equal);
1243
1244 /* get the hash of the searched node */
1245 hash = dict_hash_multi(0, lys_node_module(pp.schema)->name, strlen(lys_node_module(pp.schema)->name));
1246 hash = dict_hash_multi(hash, pp.schema->name, strlen(pp.schema->name));
1247 if (pp.schema->nodetype == LYS_LEAFLIST) {
1248 assert((pp.len == 1) && (pp.pred[0].name[0] == '.') && (pp.pred[0].nam_len == 1));
1249 /* leaf-list value in predicate */
1250 hash = dict_hash_multi(hash, pp.pred[0].value, pp.pred[0].val_len);
1251 } else if (pp.schema->nodetype == LYS_LIST) {
1252 /* list keys in predicates */
1253 for (i = 0; i < pp.len; ++i) {
1254 hash = dict_hash_multi(hash, pp.pred[i].value, pp.pred[i].val_len);
1255 }
1256 }
1257 hash = dict_hash_multi(hash, NULL, 0);
1258
1259 /* try to find the node */
Michal Vaskod60a1a32018-05-23 16:31:22 +02001260 i = lyht_find(parent->ht, &pp, hash, (void **)&ret);
1261 assert(i || *ret);
Michal Vasko2d44ee02018-05-18 09:38:51 +02001262
1263 /* restore the original callback */
1264 lyht_set_cb(parent->ht, prev_cb);
1265
Michal Vaskod60a1a32018-05-23 16:31:22 +02001266 return (i ? NULL : *ret);
Michal Vasko2d44ee02018-05-18 09:38:51 +02001267}
1268
1269#endif
1270
Radek Krejci6dc53a22015-08-17 13:27:59 +02001271/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001272 * @brief Resolve (find) a feature definition. Logs directly.
1273 *
1274 * @param[in] feat_name Feature name to resolve.
1275 * @param[in] len Length of \p feat_name.
1276 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001277 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1278 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001279 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001280 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001281 */
1282static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001283resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001284{
1285 char *str;
1286 const char *mod_name, *name;
1287 int mod_name_len, nam_len, i, j;
1288 const struct lys_module *module;
1289
Radek Krejci9ff0a922016-07-14 13:08:05 +02001290 assert(feature);
1291
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001292 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001293 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 +01001294 LOGVAL(node->module->ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001295 return -1;
1296 }
1297
Michal Vasko921eb6b2017-10-13 10:01:39 +02001298 module = lyp_get_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001299 if (!module) {
1300 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01001301 LOGVAL(node->module->ctx, LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001302 return -1;
1303 }
1304
Radek Krejci9ff0a922016-07-14 13:08:05 +02001305 if (module != node->module && module == lys_node_module(node)) {
1306 /* first, try to search directly in submodule where the feature was mentioned */
1307 for (j = 0; j < node->module->features_size; j++) {
1308 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1309 /* check status */
1310 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001311 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001312 return -1;
1313 }
1314 *feature = &node->module->features[j];
1315 return 0;
1316 }
1317 }
1318 }
1319
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001320 /* search in the identified module ... */
1321 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001322 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001323 /* check status */
1324 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001325 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001326 return -1;
1327 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001328 *feature = &module->features[j];
1329 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001330 }
1331 }
1332 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001333 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001334 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001335 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1336 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001337 /* check status */
1338 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1339 module->inc[i].submodule->features[j].flags,
1340 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001341 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001342 return -1;
1343 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001344 *feature = &module->inc[i].submodule->features[j];
1345 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001346 }
1347 }
1348 }
1349
1350 /* not found */
1351 str = strndup(feat_name, len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001352 LOGVAL(node->module->ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001353 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001354 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001355}
1356
Radek Krejci9ff0a922016-07-14 13:08:05 +02001357/*
1358 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001359 * - 1 if enabled
1360 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001361 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001362static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001363resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001364{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001365 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001366
Radek Krejci9ff0a922016-07-14 13:08:05 +02001367 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001368 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001369 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001370 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001371 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001372
Radek Krejci69b8d922016-07-27 13:13:41 +02001373 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001374}
1375
1376static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001377resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001378{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001379 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001380 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001381
Radek Krejci9ff0a922016-07-14 13:08:05 +02001382 op = iff_getop(expr->expr, *index_e);
1383 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001384
Radek Krejci9ff0a922016-07-14 13:08:05 +02001385 switch (op) {
1386 case LYS_IFF_F:
1387 /* resolve feature */
1388 return resolve_feature_value(expr->features[(*index_f)++]);
1389 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001390 /* invert result */
1391 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001392 case LYS_IFF_AND:
1393 case LYS_IFF_OR:
1394 a = resolve_iffeature_recursive(expr, index_e, index_f);
1395 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001396 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001397 return a && b;
1398 } else { /* LYS_IFF_OR */
1399 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001400 }
1401 }
1402
Radek Krejciaf566332017-02-07 15:56:59 +01001403 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001404}
1405
1406int
1407resolve_iffeature(struct lys_iffeature *expr)
1408{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001409 int index_e = 0, index_f = 0;
1410
1411 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001412 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001413 }
Radek Krejciaf566332017-02-07 15:56:59 +01001414 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001415}
1416
1417struct iff_stack {
1418 int size;
1419 int index; /* first empty item */
1420 uint8_t *stack;
1421};
1422
1423static int
1424iff_stack_push(struct iff_stack *stack, uint8_t value)
1425{
1426 if (stack->index == stack->size) {
1427 stack->size += 4;
1428 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001429 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM(NULL); stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001430 }
1431
1432 stack->stack[stack->index++] = value;
1433 return EXIT_SUCCESS;
1434}
1435
1436static uint8_t
1437iff_stack_pop(struct iff_stack *stack)
1438{
1439 stack->index--;
1440 return stack->stack[stack->index];
1441}
1442
1443static void
1444iff_stack_clean(struct iff_stack *stack)
1445{
1446 stack->size = 0;
1447 free(stack->stack);
1448}
1449
1450static void
1451iff_setop(uint8_t *list, uint8_t op, int pos)
1452{
1453 uint8_t *item;
1454 uint8_t mask = 3;
1455
1456 assert(pos >= 0);
1457 assert(op <= 3); /* max 2 bits */
1458
1459 item = &list[pos / 4];
1460 mask = mask << 2 * (pos % 4);
1461 *item = (*item) & ~mask;
1462 *item = (*item) | (op << 2 * (pos % 4));
1463}
1464
1465uint8_t
1466iff_getop(uint8_t *list, int pos)
1467{
1468 uint8_t *item;
1469 uint8_t mask = 3, result;
1470
1471 assert(pos >= 0);
1472
1473 item = &list[pos / 4];
1474 result = (*item) & (mask << 2 * (pos % 4));
1475 return result >> 2 * (pos % 4);
1476}
1477
1478#define LYS_IFF_LP 0x04 /* ( */
1479#define LYS_IFF_RP 0x08 /* ) */
1480
Radek Krejcicbb473e2016-09-16 14:48:32 +02001481/* internal structure for passing data for UNRES_IFFEAT */
1482struct unres_iffeat_data {
1483 struct lys_node *node;
1484 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001485 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001486};
1487
Radek Krejci9ff0a922016-07-14 13:08:05 +02001488void
1489resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1490{
1491 unsigned int e = 0, f = 0, r = 0;
1492 uint8_t op;
1493
1494 assert(iffeat);
1495
1496 if (!iffeat->expr) {
1497 goto result;
1498 }
1499
1500 do {
1501 op = iff_getop(iffeat->expr, e++);
1502 switch (op) {
1503 case LYS_IFF_NOT:
1504 if (!r) {
1505 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001506 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001507 break;
1508 case LYS_IFF_AND:
1509 case LYS_IFF_OR:
1510 if (!r) {
1511 r += 2;
1512 } else {
1513 r += 1;
1514 }
1515 break;
1516 case LYS_IFF_F:
1517 f++;
1518 if (r) {
1519 r--;
1520 }
1521 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001522 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001523 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001524
Radek Krejci9ff0a922016-07-14 13:08:05 +02001525result:
1526 if (expr_size) {
1527 *expr_size = e;
1528 }
1529 if (feat_size) {
1530 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001531 }
1532}
1533
1534int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001535resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001536 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001537{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001538 const char *c = value;
1539 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001540 int i, j, last_not, checkversion = 0;
1541 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001542 uint8_t op;
1543 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001544 struct unres_iffeat_data *iff_data;
Michal Vasko53b7da02018-02-13 15:28:42 +01001545 struct ly_ctx *ctx = node->module->ctx;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001546
Radek Krejci9ff0a922016-07-14 13:08:05 +02001547 assert(c);
1548
1549 if (isspace(c[0])) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001550 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001551 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001552 }
1553
Radek Krejci9ff0a922016-07-14 13:08:05 +02001554 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1555 for (i = j = last_not = 0; c[i]; i++) {
1556 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001557 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001558 j++;
1559 continue;
1560 } else if (c[i] == ')') {
1561 j--;
1562 continue;
1563 } else if (isspace(c[i])) {
1564 continue;
1565 }
1566
1567 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1568 if (c[i + r] == '\0') {
Michal Vasko53b7da02018-02-13 15:28:42 +01001569 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001570 return EXIT_FAILURE;
1571 } else if (!isspace(c[i + r])) {
1572 /* feature name starting with the not/and/or */
1573 last_not = 0;
1574 f_size++;
1575 } else if (c[i] == 'n') { /* not operation */
1576 if (last_not) {
1577 /* double not */
1578 expr_size = expr_size - 2;
1579 last_not = 0;
1580 } else {
1581 last_not = 1;
1582 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001583 } else { /* and, or */
1584 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001585 /* not a not operation */
1586 last_not = 0;
1587 }
1588 i += r;
1589 } else {
1590 f_size++;
1591 last_not = 0;
1592 }
1593 expr_size++;
1594
1595 while (!isspace(c[i])) {
1596 if (!c[i] || c[i] == ')') {
1597 i--;
1598 break;
1599 }
1600 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001601 }
1602 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001603 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001604 /* not matching count of ( and ) */
Michal Vasko53b7da02018-02-13 15:28:42 +01001605 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001606 return EXIT_FAILURE;
1607 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001608
Radek Krejci69b8d922016-07-27 13:13:41 +02001609 if (checkversion || expr_size > 1) {
1610 /* check that we have 1.1 module */
Radek Krejci13fde922018-05-16 10:45:58 +02001611 if (node->module->version != LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001612 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1613 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 +02001614 return EXIT_FAILURE;
1615 }
1616 }
1617
Radek Krejci9ff0a922016-07-14 13:08:05 +02001618 /* allocate the memory */
1619 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001620 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001621 stack.stack = malloc(expr_size * sizeof *stack.stack);
Michal Vasko53b7da02018-02-13 15:28:42 +01001622 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM(ctx), error);
Radek Krejciaa1303c2017-05-31 13:57:37 +02001623 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001624 f_size--; expr_size--; /* used as indexes from now */
1625
1626 for (i--; i >= 0; i--) {
1627 if (c[i] == ')') {
1628 /* push it on stack */
1629 iff_stack_push(&stack, LYS_IFF_RP);
1630 continue;
1631 } else if (c[i] == '(') {
1632 /* pop from the stack into result all operators until ) */
1633 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1634 iff_setop(iffeat_expr->expr, op, expr_size--);
1635 }
1636 continue;
1637 } else if (isspace(c[i])) {
1638 continue;
1639 }
1640
1641 /* end operator or operand -> find beginning and get what is it */
1642 j = i + 1;
1643 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1644 i--;
1645 }
1646 i++; /* get back by one step */
1647
Michal Vasko88011352018-07-12 08:49:07 +02001648 if (!strncmp(&c[i], "not", 3) && isspace(c[i + 3])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001649 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1650 /* double not */
1651 iff_stack_pop(&stack);
1652 } else {
1653 /* not has the highest priority, so do not pop from the stack
1654 * as in case of AND and OR */
1655 iff_stack_push(&stack, LYS_IFF_NOT);
1656 }
Michal Vasko88011352018-07-12 08:49:07 +02001657 } else if (!strncmp(&c[i], "and", 3) && isspace(c[i + 3])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001658 /* as for OR - pop from the stack all operators with the same or higher
1659 * priority and store them to the result, then push the AND to the stack */
1660 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1661 op = iff_stack_pop(&stack);
1662 iff_setop(iffeat_expr->expr, op, expr_size--);
1663 }
1664 iff_stack_push(&stack, LYS_IFF_AND);
Michal Vasko88011352018-07-12 08:49:07 +02001665 } else if (!strncmp(&c[i], "or", 2) && isspace(c[i + 2])) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001666 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1667 op = iff_stack_pop(&stack);
1668 iff_setop(iffeat_expr->expr, op, expr_size--);
1669 }
1670 iff_stack_push(&stack, LYS_IFF_OR);
1671 } else {
1672 /* feature name, length is j - i */
1673
1674 /* add it to the result */
1675 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1676
1677 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001678 * forward referenced, we have to keep the feature name in auxiliary
1679 * structure passed into unres */
1680 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01001681 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM(ctx), error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001682 iff_data->node = node;
1683 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001684 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001685 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1686 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001687 f_size--;
1688
1689 if (r == -1) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01001690 lydict_remove(node->module->ctx, iff_data->fname);
Pavol Vican4d084512016-09-29 16:38:12 +02001691 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001692 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001693 }
1694 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001695 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001696 while (stack.index) {
1697 op = iff_stack_pop(&stack);
1698 iff_setop(iffeat_expr->expr, op, expr_size--);
1699 }
1700
1701 if (++expr_size || ++f_size) {
1702 /* not all expected operators and operands found */
Michal Vasko53b7da02018-02-13 15:28:42 +01001703 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001704 rc = EXIT_FAILURE;
1705 } else {
1706 rc = EXIT_SUCCESS;
1707 }
1708
1709error:
1710 /* cleanup */
1711 iff_stack_clean(&stack);
1712
1713 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001714}
1715
1716/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001717 * @brief Resolve (find) a data node based on a schema-nodeid.
1718 *
1719 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1720 * module).
1721 *
1722 */
1723struct lyd_node *
1724resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1725{
1726 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001727 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001728 const struct lys_node *schema = NULL;
1729
1730 assert(nodeid && start);
1731
1732 if (nodeid[0] == '/') {
1733 return NULL;
1734 }
1735
1736 str = p = strdup(nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01001737 LY_CHECK_ERR_RETURN(!str, LOGMEM(start->schema->module->ctx), NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001738
Michal Vasko3edeaf72016-02-11 13:17:43 +01001739 while (p) {
1740 token = p;
1741 p = strchr(p, '/');
1742 if (p) {
1743 *p = '\0';
1744 p++;
1745 }
1746
Radek Krejci5da4eb62016-04-08 14:45:51 +02001747 if (p) {
1748 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001749 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001750 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001751 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001752 result = NULL;
1753 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001754 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001755
Radek Krejci5da4eb62016-04-08 14:45:51 +02001756 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1757 continue;
1758 }
1759 } else {
1760 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001761 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001762 || !schema) {
1763 result = NULL;
1764 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001765 }
1766 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001767 LY_TREE_FOR(result ? result->child : start, iter) {
1768 if (iter->schema == schema) {
1769 /* move in data tree according to returned schema */
1770 result = iter;
1771 break;
1772 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001774 if (!iter) {
1775 /* instance not found */
1776 result = NULL;
1777 break;
1778 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779 }
1780 free(str);
1781
1782 return result;
1783}
1784
Radek Krejci1a9c3612017-04-24 14:49:43 +02001785int
Michal Vasko50576712017-07-28 12:28:33 +02001786schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1787 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001788{
1789 const struct lys_module *prefix_mod;
1790
Michal Vaskocdb3f062018-02-01 09:55:06 +01001791 /* handle special names */
1792 if (name[0] == '*') {
1793 return 2;
1794 } else if (name[0] == '.') {
1795 return 3;
1796 }
1797
Michal Vasko50576712017-07-28 12:28:33 +02001798 /* name check */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001799 if (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02001800 return 1;
1801 }
1802
Radek Krejcibdf92362016-04-08 14:43:34 +02001803 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001804 if (mod_name) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001805 prefix_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vasko50576712017-07-28 12:28:33 +02001806 if (!prefix_mod) {
1807 return -1;
1808 }
1809 } else {
1810 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001811 }
1812 if (prefix_mod != lys_node_module(sibling)) {
1813 return 1;
1814 }
1815
Michal Vasko50576712017-07-28 12:28:33 +02001816 /* match */
Michal Vaskocdb3f062018-02-01 09:55:06 +01001817 return 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001818}
1819
Michal Vasko50576712017-07-28 12:28:33 +02001820/* keys do not have to be ordered and do not have to be all of them */
1821static int
1822resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1823 const struct lys_module *cur_module, int *nodeid_end)
1824{
1825 int mod_len, nam_len, has_predicate, r, i;
1826 const char *model, *name;
1827 struct lys_node_list *list;
1828
1829 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1830 return 1;
1831 }
1832
1833 list = (struct lys_node_list *)node;
1834 do {
1835 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1836 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001837 LOGVAL(cur_module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001838 return -1;
1839 }
1840 nodeid += r;
1841
1842 if (node->nodetype == LYS_LEAFLIST) {
1843 /* just check syntax */
1844 if (model || !name || (name[0] != '.') || has_predicate) {
1845 return 1;
1846 }
1847 break;
1848 } else {
1849 /* check the key */
1850 for (i = 0; i < list->keys_size; ++i) {
1851 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1852 continue;
1853 }
1854 if (model) {
1855 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1856 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1857 continue;
1858 }
1859 } else {
1860 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1861 continue;
1862 }
1863 }
1864
1865 /* match */
1866 break;
1867 }
1868
1869 if (i == list->keys_size) {
1870 return 1;
1871 }
1872 }
1873 } while (has_predicate);
1874
1875 if (!nodeid[0]) {
1876 *nodeid_end = 1;
1877 }
1878 return 0;
1879}
1880
Michal Vasko97234262018-02-01 09:53:01 +01001881/* start_parent - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001882 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001883int
Michal Vasko97234262018-02-01 09:53:01 +01001884resolve_schema_nodeid(const char *nodeid, const struct lys_node *start_parent, const struct lys_module *cur_module,
Michal Vasko50576712017-07-28 12:28:33 +02001885 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001886{
PavolVicanb28bbff2018-02-21 00:44:02 +01001887 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vasko97234262018-02-01 09:53:01 +01001888 const struct lys_node *sibling, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001889 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001890 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
PavolVicanb28bbff2018-02-21 00:44:02 +01001891 int yang_data_name_len, backup_mod_name_len = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001892 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidaa547a2017-09-22 15:56:27 +02001893 const struct lys_module *start_mod, *aux_mod = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02001894 char *str;
Michal Vasko53b7da02018-02-13 15:28:42 +01001895 struct ly_ctx *ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001896
Michal Vasko97234262018-02-01 09:53:01 +01001897 assert(nodeid && (start_parent || cur_module) && ret);
Michal Vasko50576712017-07-28 12:28:33 +02001898 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001899
Michal Vasko50576712017-07-28 12:28:33 +02001900 if (!cur_module) {
Michal Vasko97234262018-02-01 09:53:01 +01001901 cur_module = lys_node_module(start_parent);
Michal Vasko50576712017-07-28 12:28:33 +02001902 }
Michal Vasko53b7da02018-02-13 15:28:42 +01001903 ctx = cur_module->ctx;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001904 id = nodeid;
1905
PavolVican195cf392018-02-23 13:24:45 +01001906 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 1);
PavolVicanb28bbff2018-02-21 00:44:02 +01001907 if (r < 1) {
1908 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1909 return -1;
1910 }
1911
1912 if (name[0] == '#') {
1913 if (is_relative) {
1914 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
1915 return -1;
1916 }
1917 yang_data_name = name + 1;
1918 yang_data_name_len = nam_len - 1;
1919 backup_mod_name = mod_name;
1920 backup_mod_name_len = mod_name_len;
1921 id += r;
1922 } else {
1923 is_relative = -1;
1924 }
1925
Michal Vasko50576712017-07-28 12:28:33 +02001926 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1927 (extended ? &all_desc : NULL), extended);
1928 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001929 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02001930 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001931 }
1932 id += r;
1933
PavolVicanb28bbff2018-02-21 00:44:02 +01001934 if (backup_mod_name) {
1935 mod_name = backup_mod_name;
1936 mod_name_len = backup_mod_name_len;
1937 }
1938
Michal Vasko97234262018-02-01 09:53:01 +01001939 if (is_relative && !start_parent) {
Michal Vasko53b7da02018-02-13 15:28:42 +01001940 LOGVAL(ctx, LYE_SPEC, LY_VLOG_STR, nodeid, "Starting node must be provided for relative paths.");
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 return -1;
1942 }
1943
1944 /* descendant-schema-nodeid */
1945 if (is_relative) {
Michal Vasko97234262018-02-01 09:53:01 +01001946 cur_module = start_mod = lys_node_module(start_parent);
Michal Vasko24476fa2017-03-08 12:33:48 +01001947
Michal Vasko3edeaf72016-02-11 13:17:43 +01001948 /* absolute-schema-nodeid */
1949 } else {
Michal Vasko921eb6b2017-10-13 10:01:39 +02001950 start_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01001951 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001952 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001953 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001954 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001955 return -1;
1956 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001957 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01001958 if (yang_data_name) {
1959 start_parent = lyp_get_yang_data_template(start_mod, yang_data_name, yang_data_name_len);
1960 if (!start_parent) {
1961 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
1962 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
1963 free(str);
1964 return -1;
1965 }
1966 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001967 }
1968
1969 while (1) {
1970 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001971 last_aug = NULL;
1972
1973 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001974 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1975 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001976 /* we are getting into another module (augment) */
Michal Vasko921eb6b2017-10-13 10:01:39 +02001977 aux_mod = lyp_get_module(cur_module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskobb520442017-05-23 10:55:18 +02001978 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001979 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01001980 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02001981 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001982 return -1;
1983 }
1984 } else {
Michal Vasko201c3392017-07-10 15:15:39 +02001985 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001986 * because this module may be not implemented and it augments something in another module and
1987 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001988 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001989 }
1990
Michal Vasko3b2ad462018-07-10 15:40:53 +02001991 /* look into augments */
1992 if (!extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001993get_next_augment:
1994 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1995 }
1996 }
1997
1998 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vaskocb45f472018-02-12 10:47:42 +01001999 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002000 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
2001
2002 /* resolve predicate */
2003 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
2004 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
2005 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002006 continue;
Michal Vasko50576712017-07-28 12:28:33 +02002007 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002008 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002009 }
Michal Vasko50576712017-07-28 12:28:33 +02002010 } else if (!id[0]) {
2011 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002012 }
Michal Vasko50576712017-07-28 12:28:33 +02002013
2014 if (r == 0) {
2015 /* one matching result */
2016 if (nodeid_end) {
2017 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002018 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002019 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2020 } else {
2021 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2022 return -1;
2023 }
2024 start_parent = sibling;
2025 }
2026 break;
2027 } else if (r == 1) {
2028 continue;
2029 } else if (r == 2) {
2030 /* "*" */
2031 if (!*ret) {
2032 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002033 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002034 }
2035 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2036 if (all_desc) {
2037 LY_TREE_DFS_BEGIN(sibling, next, elem) {
2038 if (elem != sibling) {
2039 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2040 }
2041
2042 LY_TREE_DFS_END(sibling, next, elem);
2043 }
2044 }
2045 } else if (r == 3) {
2046 /* "." */
2047 if (!*ret) {
2048 *ret = ly_set_new();
Michal Vasko53b7da02018-02-13 15:28:42 +01002049 LY_CHECK_ERR_RETURN(!*ret, LOGMEM(ctx), -1);
Michal Vasko50576712017-07-28 12:28:33 +02002050 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
2051 }
2052 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
2053 if (all_desc) {
2054 LY_TREE_DFS_BEGIN(sibling, next, elem) {
2055 if (elem != sibling) {
2056 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
2057 }
2058
2059 LY_TREE_DFS_END(sibling, next, elem);
2060 }
2061 }
2062 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002063 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02002064 return -1;
2065 }
2066 }
2067
2068 /* skip predicate */
2069 if (extended && has_predicate) {
2070 while (id[0] == '[') {
2071 id = strchr(id, ']');
2072 if (!id) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002073 LOGINT(ctx);
Michal Vasko50576712017-07-28 12:28:33 +02002074 return -1;
2075 }
2076 ++id;
2077 }
2078 }
2079
2080 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
2081 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002082 }
2083
2084 /* no match */
2085 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02002086 if (last_aug) {
2087 /* it still could be in another augment */
2088 goto get_next_augment;
2089 }
Michal Vasko50576712017-07-28 12:28:33 +02002090 if (no_node_error) {
2091 str = strndup(nodeid, (name - nodeid) + nam_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01002092 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko50576712017-07-28 12:28:33 +02002093 free(str);
2094 return -1;
2095 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01002096 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002097 return EXIT_SUCCESS;
2098 }
2099
Michal Vasko50576712017-07-28 12:28:33 +02002100 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
2101 (extended ? &all_desc : NULL), extended);
2102 if (r < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002103 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
Michal Vasko50576712017-07-28 12:28:33 +02002104 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002105 }
2106 id += r;
2107 }
2108
2109 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002110 LOGINT(ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002111 return -1;
2112}
2113
Radek Krejcif3c71de2016-04-11 12:45:46 +02002114/* unique, refine,
2115 * >0 - unexpected char on position (ret - 1),
2116 * 0 - ok (but ret can still be NULL),
2117 * -1 - error,
2118 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01002119int
2120resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02002121 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002122{
2123 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002124 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002125 int r, nam_len, mod_name_len, is_relative = -1;
2126 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02002127 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002128
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002129 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01002130 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01002131
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01002132 if (!start) {
2133 /* leaf not found */
2134 return 0;
2135 }
2136
Michal Vasko3edeaf72016-02-11 13:17:43 +01002137 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02002138 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002139
Michal Vasko50576712017-07-28 12:28:33 +02002140 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 +01002141 return ((id - nodeid) - r) + 1;
2142 }
2143 id += r;
2144
2145 if (!is_relative) {
2146 return -1;
2147 }
2148
Michal Vasko24476fa2017-03-08 12:33:48 +01002149 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02002150 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01002151 start_parent = lys_parent(start_parent);
2152 }
2153
Michal Vasko3edeaf72016-02-11 13:17:43 +01002154 while (1) {
2155 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002156 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vaskocb45f472018-02-12 10:47:42 +01002157 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002158 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2159 if (r == 0) {
2160 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002161 if (!(sibling->nodetype & ret_nodetype)) {
2162 /* wrong node type, too bad */
2163 continue;
2164 }
2165 *ret = sibling;
2166 return EXIT_SUCCESS;
2167 }
Michal Vasko50576712017-07-28 12:28:33 +02002168 start_parent = sibling;
2169 break;
2170 } else if (r == 1) {
2171 continue;
2172 } else {
2173 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002174 }
2175 }
2176
2177 /* no match */
2178 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002179 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002180 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02002181 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
2182 *ret = NULL;
2183 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002184 }
2185
Michal Vasko50576712017-07-28 12:28:33 +02002186 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 +01002187 return ((id - nodeid) - r) + 1;
2188 }
2189 id += r;
2190 }
2191
2192 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002193 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002194 return -1;
2195}
2196
2197/* choice default */
2198int
2199resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2200{
2201 /* cannot actually be a path */
2202 if (strchr(nodeid, '/')) {
2203 return -1;
2204 }
2205
Michal Vaskodc300b02017-04-07 14:09:20 +02002206 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002207}
2208
2209/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2210static int
2211resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2212{
2213 const struct lys_module *module;
2214 const char *mod_prefix, *name;
2215 int i, mod_prefix_len, nam_len;
2216
2217 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002218 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 +01002219 return -i + 1;
2220 }
2221
Michal Vasko921eb6b2017-10-13 10:01:39 +02002222 module = lyp_get_module(start->module, mod_prefix, mod_prefix_len, NULL, 0, 0);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002223 if (!module) {
2224 return -1;
2225 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002226 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002227 start = module->data;
2228 }
2229
2230 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2231
2232 return EXIT_SUCCESS;
2233}
2234
2235int
2236resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2237 const struct lys_node **ret)
2238{
2239 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002240 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002241 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002242 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002243
2244 assert(nodeid && module && ret);
2245 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2246
2247 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002248 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002249
Michal Vasko50576712017-07-28 12:28:33 +02002250 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 +01002251 return ((id - nodeid) - r) + 1;
2252 }
2253 id += r;
2254
2255 if (is_relative) {
2256 return -1;
2257 }
2258
Michal Vasko921eb6b2017-10-13 10:01:39 +02002259 abs_start_mod = lyp_get_module(module, NULL, 0, mod_name, mod_name_len, 0);
Michal Vaskoe2905632016-02-11 15:42:24 +01002260 if (!abs_start_mod) {
2261 return -1;
2262 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002263
2264 while (1) {
2265 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002266 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vaskocb45f472018-02-12 10:47:42 +01002267 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING | LYS_GETNEXT_NOSTATECHECK))) {
Michal Vasko50576712017-07-28 12:28:33 +02002268 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2269 if (r == 0) {
2270 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002271 if (!(sibling->nodetype & ret_nodetype)) {
2272 /* wrong node type, too bad */
2273 continue;
2274 }
2275 *ret = sibling;
2276 return EXIT_SUCCESS;
2277 }
Michal Vasko50576712017-07-28 12:28:33 +02002278 start_parent = sibling;
2279 break;
2280 } else if (r == 1) {
2281 continue;
2282 } else {
2283 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002284 }
2285 }
2286
2287 /* no match */
2288 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002289 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002290 return EXIT_SUCCESS;
2291 }
2292
Michal Vasko50576712017-07-28 12:28:33 +02002293 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 +01002294 return ((id - nodeid) - r) + 1;
2295 }
2296 id += r;
2297 }
2298
2299 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002300 LOGINT(module->ctx);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002301 return -1;
2302}
2303
Michal Vaskoe733d682016-03-14 09:08:27 +01002304static int
Michal Vaskof68a49e2017-08-14 13:23:37 +02002305resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002306{
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002307 const char *mod_name, *name;
2308 int mod_name_len, nam_len, has_predicate, i;
2309 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002310
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002311 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 +02002312 || !strncmp(name, ".", nam_len)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002313 LOGVAL(list->module->ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002314 return -1;
2315 }
2316
2317 predicate += i;
2318 *parsed += i;
2319
Michal Vasko58c2aab2017-01-05 10:02:05 +01002320 if (!isdigit(name[0])) {
2321 for (i = 0; i < list->keys_size; ++i) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002322 key = (struct lys_node *)list->keys[i];
2323 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002324 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002325 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002326 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002327
Michal Vasko58c2aab2017-01-05 10:02:05 +01002328 if (i == list->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002329 LOGVAL(list->module->ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko58c2aab2017-01-05 10:02:05 +01002330 return -1;
2331 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002332 }
2333
2334 /* more predicates? */
2335 if (has_predicate) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002336 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002337 }
2338
2339 return 0;
2340}
2341
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002342/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002343const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002344resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002345{
Michal Vasko53b7da02018-02-13 15:28:42 +01002346 char *str;
PavolVicanb28bbff2018-02-21 00:44:02 +01002347 const char *name, *mod_name, *id, *backup_mod_name = NULL, *yang_data_name = NULL;
Michal Vaskob3744402017-08-03 14:23:58 +02002348 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002349 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
PavolVicanb28bbff2018-02-21 00:44:02 +01002350 int yang_data_name_len, backup_mod_name_len;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002351 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskof68a49e2017-08-14 13:23:37 +02002352 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002353
Michal Vasko3547c532016-03-14 09:40:50 +01002354 assert(nodeid && (ctx || start));
2355 if (!ctx) {
2356 ctx = start->module->ctx;
2357 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002358
2359 id = nodeid;
2360
PavolVican195cf392018-02-23 13:24:45 +01002361 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 +01002362 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2363 return NULL;
2364 }
2365
2366 if (name[0] == '#') {
2367 if (is_relative) {
2368 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
2369 return NULL;
2370 }
2371 yang_data_name = name + 1;
2372 yang_data_name_len = nam_len - 1;
2373 backup_mod_name = mod_name;
2374 backup_mod_name_len = mod_name_len;
2375 id += r;
2376 } else {
2377 is_relative = -1;
2378 }
2379
Michal Vasko50576712017-07-28 12:28:33 +02002380 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 +01002381 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002382 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002383 }
2384 id += r;
2385
PavolVicanb28bbff2018-02-21 00:44:02 +01002386 if (backup_mod_name) {
2387 mod_name = backup_mod_name;
2388 mod_name_len = backup_mod_name_len;
2389 }
2390
Michal Vasko3edeaf72016-02-11 13:17:43 +01002391 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002392 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002393 start_parent = start;
2394 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2395 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002396 }
Michal Vaskof68a49e2017-08-14 13:23:37 +02002397 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002398 } else {
2399 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002400 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002401 LOGVAL(ctx, LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
Michal Vasko10728b52016-04-07 14:26:29 +02002402 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002403 return NULL;
2404 }
2405
Michal Vasko53b7da02018-02-13 15:28:42 +01002406 str = strndup(mod_name, mod_name_len);
2407 module = ly_ctx_get_module(ctx, str, NULL, 1);
2408 free(str);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002409
Michal Vaskof68a49e2017-08-14 13:23:37 +02002410 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002411 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002412 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002413 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002414 return NULL;
2415 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002416 start_parent = NULL;
PavolVicanb28bbff2018-02-21 00:44:02 +01002417 if (yang_data_name) {
2418 start_parent = lyp_get_yang_data_template(module, yang_data_name, yang_data_name_len);
2419 if (!start_parent) {
2420 str = strndup(nodeid, (yang_data_name + yang_data_name_len) - nodeid);
2421 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
2422 free(str);
2423 return NULL;
2424 }
2425 }
Michal Vasko3547c532016-03-14 09:40:50 +01002426
2427 /* now it's as if there was no module name */
2428 mod_name = NULL;
2429 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002430 }
2431
Michal Vaskof68a49e2017-08-14 13:23:37 +02002432 prev_mod = module;
2433
Michal Vasko3edeaf72016-02-11 13:17:43 +01002434 while (1) {
2435 sibling = NULL;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002436 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002437 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002438 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002439 /* output check */
2440 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2441 if (parent) {
2442 if (output && (parent->nodetype == LYS_INPUT)) {
2443 continue;
2444 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2445 continue;
2446 }
2447 }
2448
Michal Vasko3edeaf72016-02-11 13:17:43 +01002449 /* module check */
2450 if (mod_name) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002451 /* will also find an augment module */
Michal Vasko53b7da02018-02-13 15:28:42 +01002452 prefix_mod = ly_ctx_nget_module(ctx, mod_name, mod_name_len, NULL, 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002453
Michal Vasko3edeaf72016-02-11 13:17:43 +01002454 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002455 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002456 LOGVAL(ctx, LYE_PATH_INMOD, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002457 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002458 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002459 }
2460 } else {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002461 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002462 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002463 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002464 continue;
2465 }
2466
Michal Vaskoe733d682016-03-14 09:08:27 +01002467 /* do we have some predicates on it? */
2468 if (has_predicate) {
2469 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002470 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002471 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002472 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002473 return NULL;
2474 }
2475 } else if (sibling->nodetype == LYS_LIST) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002476 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002477 return NULL;
2478 }
2479 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01002480 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002481 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002482 }
2483 id += r;
2484 }
2485
Michal Vasko3edeaf72016-02-11 13:17:43 +01002486 /* the result node? */
2487 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002488 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002489 }
2490
Michal Vaskodc300b02017-04-07 14:09:20 +02002491 /* move down the tree, if possible */
2492 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01002493 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskodc300b02017-04-07 14:09:20 +02002494 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002495 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002496 start_parent = sibling;
Michal Vaskof68a49e2017-08-14 13:23:37 +02002497
2498 /* update prev mod */
2499 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002500 break;
2501 }
2502 }
2503
2504 /* no match */
2505 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002506 str = strndup(nodeid, (name + nam_len) - nodeid);
Michal Vasko53b7da02018-02-13 15:28:42 +01002507 LOGVAL(ctx, LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko10728b52016-04-07 14:26:29 +02002508 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002509 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002510 }
2511
Michal Vasko50576712017-07-28 12:28:33 +02002512 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 +01002513 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002514 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002515 }
2516 id += r;
2517 }
2518
2519 /* cannot get here */
Michal Vasko53b7da02018-02-13 15:28:42 +01002520 LOGINT(ctx);
Michal Vaskoe733d682016-03-14 09:08:27 +01002521 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002522}
2523
Michal Vasko22448d32016-03-16 13:17:29 +01002524static int
Michal Vasko2d44ee02018-05-18 09:38:51 +02002525resolve_partial_json_data_list_predicate(struct parsed_pred pp, struct lyd_node *node, int position)
Michal Vasko22448d32016-03-16 13:17:29 +01002526{
Michal Vasko22448d32016-03-16 13:17:29 +01002527 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002528 struct lyd_node_leaf_list *key;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002529 struct lys_node_list *slist;
Michal Vasko53b7da02018-02-13 15:28:42 +01002530 struct ly_ctx *ctx;
Michal Vasko22448d32016-03-16 13:17:29 +01002531
Radek Krejci61a86c62016-03-24 11:06:44 +01002532 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002533 assert(node->schema->nodetype == LYS_LIST);
Michal Vasko2d44ee02018-05-18 09:38:51 +02002534 assert(pp.len);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002535
Michal Vasko53b7da02018-02-13 15:28:42 +01002536 ctx = node->schema->module->ctx;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002537 slist = (struct lys_node_list *)node->schema;
Michal Vasko22448d32016-03-16 13:17:29 +01002538
Michal Vasko53adfc72017-01-06 10:39:10 +01002539 /* is the predicate a number? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002540 if (isdigit(pp.pred[0].name[0])) {
2541 if (position == atoi(pp.pred[0].name)) {
Michal Vasko53adfc72017-01-06 10:39:10 +01002542 /* match */
Michal Vasko53adfc72017-01-06 10:39:10 +01002543 return 0;
2544 } else {
2545 /* not a match */
2546 return 1;
2547 }
2548 }
2549
Michal Vaskof29903d2016-04-18 13:13:10 +02002550 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002551 if (!key) {
2552 /* it is not a position, so we need a key for it to be a match */
2553 return 1;
2554 }
2555
2556 /* go through all the keys */
Michal Vaskofebd13d2018-05-17 10:42:24 +02002557 for (i = 0; i < slist->keys_size; ++i) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002558 if (strncmp(key->schema->name, pp.pred[i].name, pp.pred[i].nam_len) || key->schema->name[pp.pred[i].nam_len]) {
2559 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002560 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002561 }
2562
Michal Vasko2d44ee02018-05-18 09:38:51 +02002563 if (pp.pred[i].mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002564 /* specific module, check that the found key is from that module */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002565 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, pp.pred[i].mod_name, pp.pred[i].mod_name_len)
2566 || lyd_node_module((struct lyd_node *)key)->name[pp.pred[i].mod_name_len]) {
2567 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002568 return -1;
2569 }
Michal Vasko50576712017-07-28 12:28:33 +02002570
2571 /* but if the module is the same as the parent, it should have been omitted */
2572 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002573 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko50576712017-07-28 12:28:33 +02002574 return -1;
2575 }
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002576 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002577 /* no module, so it must be the same as the list (parent) */
2578 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002579 LOGVAL(ctx, LYE_PATH_INKEY, LY_VLOG_NONE, NULL, pp.pred[i].name);
Michal Vasko9fbb6e82017-07-04 13:50:04 +02002580 return -1;
2581 }
2582 }
2583
Michal Vasko22448d32016-03-16 13:17:29 +01002584 /* value does not match */
Michal Vasko310bc582018-05-22 10:47:59 +02002585 if (strncmp(key->value_str, pp.pred[i].value, pp.pred[i].val_len) || key->value_str[pp.pred[i].val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002586 return 1;
2587 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002588
2589 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002590 }
2591
Michal Vasko22448d32016-03-16 13:17:29 +01002592 return 0;
2593}
2594
Radek Krejci45826012016-08-24 15:07:57 +02002595/**
2596 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2597 *
2598 * @param[in] nodeid Node data path to find
2599 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2600 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2601 * @param[out] parsed Number of characters processed in \p id
2602 * @return The closes parent (or the node itself) from the path
2603 */
Michal Vasko22448d32016-03-16 13:17:29 +01002604struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002605resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2606 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002607{
Michal Vasko2d44ee02018-05-18 09:38:51 +02002608 const char *id, *mod_name, *name, *data_val, *llval;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002609 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002610 int has_predicate, last_parsed = 0, llval_len;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002611 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002612 struct lyd_node_leaf_list *llist;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002613 const struct lys_module *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002614 struct ly_ctx *ctx;
Michal Vasko20964782018-08-01 15:14:30 +02002615 const struct lys_node *ssibling, *sparent;
Michal Vasko310bc582018-05-22 10:47:59 +02002616 struct lys_node_list *slist;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002617 struct parsed_pred pp;
Michal Vasko22448d32016-03-16 13:17:29 +01002618
2619 assert(nodeid && start && parsed);
2620
Michal Vasko2d44ee02018-05-18 09:38:51 +02002621 memset(&pp, 0, sizeof pp);
Michal Vasko22448d32016-03-16 13:17:29 +01002622 ctx = start->schema->module->ctx;
2623 id = nodeid;
2624
Michal Vasko2d44ee02018-05-18 09:38:51 +02002625 /* parse first nodeid in case it is yang-data extension */
PavolVican195cf392018-02-23 13:24:45 +01002626 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 +01002627 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002628 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002629 }
2630
2631 if (name[0] == '#') {
2632 if (is_relative) {
2633 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, '#', name);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002634 goto error;
PavolVicanb28bbff2018-02-21 00:44:02 +01002635 }
PavolVicanb28bbff2018-02-21 00:44:02 +01002636 id += r;
2637 last_parsed = r;
2638 } else {
2639 is_relative = -1;
2640 }
2641
Michal Vasko2d44ee02018-05-18 09:38:51 +02002642 /* parse first nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002643 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 +01002644 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002645 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002646 }
2647 id += r;
2648 /* add it to parsed only after the data node was actually found */
PavolVicanb28bbff2018-02-21 00:44:02 +01002649 last_parsed += r;
Michal Vasko22448d32016-03-16 13:17:29 +01002650
2651 if (is_relative) {
Michal Vaskof68a49e2017-08-14 13:23:37 +02002652 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002653 start = start->child;
2654 } else {
2655 for (; start->parent; start = start->parent);
Michal Vaskof68a49e2017-08-14 13:23:37 +02002656 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002657 }
2658
Michal Vaskofebd13d2018-05-17 10:42:24 +02002659 /* do not duplicate code, use predicate parsing from the loop */
2660 goto parse_predicates;
2661
Michal Vasko22448d32016-03-16 13:17:29 +01002662 while (1) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002663 /* find the correct schema node first */
2664 ssibling = NULL;
Michal Vasko20964782018-08-01 15:14:30 +02002665 sparent = (start && start->parent) ? start->parent->schema : NULL;
2666 while ((ssibling = lys_getnext(ssibling, sparent, prev_mod, 0))) {
2667 /* skip invalid input/output nodes */
2668 if (sparent && (sparent->nodetype & (LYS_RPC | LYS_ACTION))) {
2669 if (options & LYD_PATH_OPT_OUTPUT) {
2670 if (lys_parent(ssibling)->nodetype == LYS_INPUT) {
2671 continue;
2672 }
2673 } else {
2674 if (lys_parent(ssibling)->nodetype == LYS_OUTPUT) {
2675 continue;
2676 }
2677 }
2678 }
2679
Michal Vasko2d44ee02018-05-18 09:38:51 +02002680 if (!schema_nodeid_siblingcheck(ssibling, prev_mod, mod_name, mod_name_len, name, nam_len)) {
2681 break;
Michal Vasko2411b942016-03-23 13:50:03 +01002682 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002683 }
2684 if (!ssibling) {
2685 /* there is not even such a schema node */
2686 free(pp.pred);
2687 return last_match;
2688 }
2689 pp.schema = ssibling;
Michal Vasko2411b942016-03-23 13:50:03 +01002690
Michal Vasko2d44ee02018-05-18 09:38:51 +02002691 /* unify leaf-list value - it is possible to specify last-node value as both a predicate or parameter if
2692 * is a leaf-list, unify both cases and the value will in both cases be in the predicate structure */
2693 if (!id[0] && !pp.len && (ssibling->nodetype == LYS_LEAFLIST)) {
2694 pp.len = 1;
2695 pp.pred = calloc(1, sizeof *pp.pred);
2696 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
Michal Vasko22448d32016-03-16 13:17:29 +01002697
Michal Vasko2d44ee02018-05-18 09:38:51 +02002698 pp.pred[0].name = ".";
2699 pp.pred[0].nam_len = 1;
2700 pp.pred[0].value = (llist_value ? llist_value : "");
2701 pp.pred[0].val_len = strlen(pp.pred[0].value);
2702 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002703
Michal Vasko310bc582018-05-22 10:47:59 +02002704 if (ssibling->nodetype & (LYS_LEAFLIST | LYS_LEAF)) {
2705 /* check leaf/leaf-list predicate */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002706 if (pp.len > 1) {
2707 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2708 goto error;
Michal Vasko310bc582018-05-22 10:47:59 +02002709 } else if (pp.len) {
2710 if ((pp.pred[0].name[0] != '.') || (pp.pred[0].nam_len != 1)) {
2711 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, pp.pred[0].name[0], pp.pred[0].name);
2712 goto error;
2713 }
2714 if ((((struct lys_node_leaf *)ssibling)->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[0].value, ':', pp.pred[0].val_len)) {
2715 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, ssibling, pp.pred[0].val_len, pp.pred[0].value);
2716 goto error;
2717 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002718 }
2719 } else if (ssibling->nodetype == LYS_LIST) {
Michal Vasko310bc582018-05-22 10:47:59 +02002720 /* list should have predicates for all the keys or position */
2721 slist = (struct lys_node_list *)ssibling;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002722 if (!pp.len) {
2723 /* none match */
2724 return last_match;
Michal Vasko310bc582018-05-22 10:47:59 +02002725 } else if (!isdigit(pp.pred[0].name[0])) {
2726 /* list predicate is not a position, so there must be all the keys */
2727 if (pp.len > slist->keys_size) {
2728 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2729 goto error;
2730 } else if (pp.len < slist->keys_size) {
2731 LOGVAL(ctx, LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, slist->keys[pp.len]->name);
2732 goto error;
2733 }
2734 /* check that all identityrefs have module name, otherwise the hash of the list instance will never match!! */
2735 for (r = 0; r < pp.len; ++r) {
2736 if ((slist->keys[r]->type.base == LY_TYPE_IDENT) && !strnchr(pp.pred[r].value, ':', pp.pred[r].val_len)) {
2737 LOGVAL(ctx, LYE_PATH_INIDENTREF, LY_VLOG_LYS, slist->keys[r], pp.pred[r].val_len, pp.pred[r].value);
2738 goto error;
2739 }
2740 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002741 }
2742 } else if (pp.pred) {
2743 /* no other nodes allow predicates */
2744 LOGVAL(ctx, LYE_PATH_PREDTOOMANY, LY_VLOG_NONE, NULL);
2745 goto error;
2746 }
2747
2748#ifdef LY_ENABLED_CACHE
2749 /* we will not be matching keyless lists or state leaf-lists this way */
2750 if (start->parent && start->parent->ht && ((pp.schema->nodetype != LYS_LIST) || ((struct lys_node_list *)pp.schema)->keys_size)
2751 && ((pp.schema->nodetype != LYS_LEAFLIST) || (pp.schema->flags & LYS_CONFIG_W))) {
2752 sibling = resolve_json_data_node_hash(start->parent, pp);
2753 } else
2754#endif
2755 {
2756 list_instance_position = 0;
2757 LY_TREE_FOR(start, sibling) {
2758 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
2759 if (lys_parent(sibling->schema)) {
2760 if (options & LYD_PATH_OPT_OUTPUT) {
2761 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
2762 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
2763 goto error;
2764 }
2765 } else {
2766 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
2767 LOGERR(ctx, LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
2768 goto error;
2769 }
Michal Vasko22448d32016-03-16 13:17:29 +01002770 }
Michal Vasko22448d32016-03-16 13:17:29 +01002771 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002772
2773 if (sibling->schema != ssibling) {
2774 /* wrong schema node */
Michal Vasko22448d32016-03-16 13:17:29 +01002775 continue;
2776 }
2777
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002778 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002779 if (ssibling->nodetype == LYS_LEAFLIST) {
2780 if (ssibling->flags & LYS_CONFIG_R) {
Michal Vasko24affa02018-04-03 09:06:06 +02002781 /* state leaf-lists will never match */
2782 continue;
2783 }
2784
Michal Vasko9ba34de2016-12-07 12:21:19 +01002785 llist = (struct lyd_node_leaf_list *)sibling;
2786
Michal Vasko2d44ee02018-05-18 09:38:51 +02002787 /* get the expected leaf-list value */
2788 llval = NULL;
2789 llval_len = 0;
2790 if (pp.pred) {
2791 /* it was already checked that it is correct */
2792 llval = pp.pred[0].value;
2793 llval_len = pp.pred[0].val_len;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002794
Michal Vaskof0a50972016-10-19 11:33:55 +02002795 }
2796
Michal Vasko21b90ce2017-09-19 09:38:27 +02002797 /* make value canonical (remove module name prefix) unless it was specified with it */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002798 if (llval && !strchr(llval, ':') && (llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002799 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2800 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002801 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2802 } else {
2803 data_val = llist->value_str;
2804 }
2805
Michal Vasko2d44ee02018-05-18 09:38:51 +02002806 if ((!llval && data_val && data_val[0]) || (llval && (strncmp(llval, data_val, llval_len)
2807 || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002808 continue;
2809 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002810
Michal Vasko2d44ee02018-05-18 09:38:51 +02002811 } else if (ssibling->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002812 /* 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 +01002813 ++list_instance_position;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002814 ret = resolve_partial_json_data_list_predicate(pp, sibling, list_instance_position);
Michal Vasko22448d32016-03-16 13:17:29 +01002815 if (ret == -1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002816 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002817 } else if (ret == 1) {
2818 /* this list instance does not match */
2819 continue;
2820 }
Michal Vasko22448d32016-03-16 13:17:29 +01002821 }
2822
Michal Vasko22448d32016-03-16 13:17:29 +01002823 break;
2824 }
2825 }
2826
2827 /* no match, return last match */
2828 if (!sibling) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002829 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002830 return last_match;
2831 }
2832
Michal Vasko2d44ee02018-05-18 09:38:51 +02002833 /* we found a next matching node */
2834 *parsed += last_parsed;
Michal Vasko586831d2018-05-22 11:13:16 +02002835 last_match = sibling;
2836 prev_mod = lyd_node_module(sibling);
Michal Vasko2d44ee02018-05-18 09:38:51 +02002837
2838 /* the result node? */
2839 if (!id[0]) {
2840 free(pp.pred);
Michal Vasko586831d2018-05-22 11:13:16 +02002841 return last_match;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002842 }
2843
Michal Vasko586831d2018-05-22 11:13:16 +02002844 /* move down the tree, if possible, and continue */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002845 if (ssibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko586831d2018-05-22 11:13:16 +02002846 /* there can be no children even through expected, error */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002847 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2848 goto error;
Michal Vasko586831d2018-05-22 11:13:16 +02002849 } else if (!sibling->child) {
2850 /* there could be some children, but are not, return what we found so far */
2851 free(pp.pred);
2852 return last_match;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002853 }
Michal Vasko2d44ee02018-05-18 09:38:51 +02002854 start = sibling->child;
2855
Michal Vaskofebd13d2018-05-17 10:42:24 +02002856 /* parse nodeid */
Michal Vasko50576712017-07-28 12:28:33 +02002857 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 +01002858 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskofebd13d2018-05-17 10:42:24 +02002859 goto error;
Michal Vasko22448d32016-03-16 13:17:29 +01002860 }
2861 id += r;
2862 last_parsed = r;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002863
2864parse_predicates:
2865 /* parse all the predicates */
Michal Vasko2d44ee02018-05-18 09:38:51 +02002866 free(pp.pred);
2867 pp.schema = NULL;
2868 pp.len = 0;
2869 pp.pred = NULL;
Michal Vaskofebd13d2018-05-17 10:42:24 +02002870 while (has_predicate) {
Michal Vasko2d44ee02018-05-18 09:38:51 +02002871 ++pp.len;
2872 pp.pred = ly_realloc(pp.pred, pp.len * sizeof *pp.pred);
2873 LY_CHECK_ERR_GOTO(!pp.pred, LOGMEM(ctx), error);
2874 if ((r = parse_schema_json_predicate(id, &pp.pred[pp.len - 1].mod_name, &pp.pred[pp.len - 1].mod_name_len,
2875 &pp.pred[pp.len - 1].name, &pp.pred[pp.len - 1].nam_len, &pp.pred[pp.len - 1].value,
2876 &pp.pred[pp.len - 1].val_len, &has_predicate)) < 1) {
Michal Vaskofebd13d2018-05-17 10:42:24 +02002877 LOGVAL(ctx, LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2878 goto error;
2879 }
2880
2881 id += r;
2882 last_parsed += r;
2883 }
Michal Vasko22448d32016-03-16 13:17:29 +01002884 }
2885
Michal Vaskofebd13d2018-05-17 10:42:24 +02002886error:
Michal Vasko238bd2f2016-03-23 09:39:01 +01002887 *parsed = -1;
Michal Vasko2d44ee02018-05-18 09:38:51 +02002888 free(pp.pred);
Michal Vasko22448d32016-03-16 13:17:29 +01002889 return NULL;
2890}
2891
Michal Vasko3edeaf72016-02-11 13:17:43 +01002892/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002893 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002894 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002895 *
Michal Vasko53b7da02018-02-13 15:28:42 +01002896 * @param[in] ctx Context for errors.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002897 * @param[in] str_restr Restriction as a string.
2898 * @param[in] type Type of the restriction.
2899 * @param[out] ret Final interval structure that starts with
2900 * the interval of the initial type, continues with intervals
2901 * of any superior types derived from the initial one, and
2902 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002903 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002904 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002905 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002906int
Michal Vasko53b7da02018-02-13 15:28:42 +01002907resolve_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 +02002908{
2909 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002910 int kind;
Michal Vaskof75b2772018-03-14 09:55:33 +01002911 int64_t local_smin = 0, local_smax = 0, local_fmin, local_fmax;
2912 uint64_t local_umin, local_umax = 0;
2913 uint8_t local_fdig = 0;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002914 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002915 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002916
2917 switch (type->base) {
2918 case LY_TYPE_BINARY:
2919 kind = 0;
2920 local_umin = 0;
2921 local_umax = 18446744073709551615UL;
2922
2923 if (!str_restr && type->info.binary.length) {
2924 str_restr = type->info.binary.length->expr;
2925 }
2926 break;
2927 case LY_TYPE_DEC64:
2928 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002929 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2930 local_fmax = __INT64_C(9223372036854775807);
2931 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002932
2933 if (!str_restr && type->info.dec64.range) {
2934 str_restr = type->info.dec64.range->expr;
2935 }
2936 break;
2937 case LY_TYPE_INT8:
2938 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002939 local_smin = __INT64_C(-128);
2940 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002941
2942 if (!str_restr && type->info.num.range) {
2943 str_restr = type->info.num.range->expr;
2944 }
2945 break;
2946 case LY_TYPE_INT16:
2947 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002948 local_smin = __INT64_C(-32768);
2949 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002950
2951 if (!str_restr && type->info.num.range) {
2952 str_restr = type->info.num.range->expr;
2953 }
2954 break;
2955 case LY_TYPE_INT32:
2956 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002957 local_smin = __INT64_C(-2147483648);
2958 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002959
2960 if (!str_restr && type->info.num.range) {
2961 str_restr = type->info.num.range->expr;
2962 }
2963 break;
2964 case LY_TYPE_INT64:
2965 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002966 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2967 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002968
2969 if (!str_restr && type->info.num.range) {
2970 str_restr = type->info.num.range->expr;
2971 }
2972 break;
2973 case LY_TYPE_UINT8:
2974 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002975 local_umin = __UINT64_C(0);
2976 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002977
2978 if (!str_restr && type->info.num.range) {
2979 str_restr = type->info.num.range->expr;
2980 }
2981 break;
2982 case LY_TYPE_UINT16:
2983 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002984 local_umin = __UINT64_C(0);
2985 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002986
2987 if (!str_restr && type->info.num.range) {
2988 str_restr = type->info.num.range->expr;
2989 }
2990 break;
2991 case LY_TYPE_UINT32:
2992 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002993 local_umin = __UINT64_C(0);
2994 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002995
2996 if (!str_restr && type->info.num.range) {
2997 str_restr = type->info.num.range->expr;
2998 }
2999 break;
3000 case LY_TYPE_UINT64:
3001 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01003002 local_umin = __UINT64_C(0);
3003 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003004
3005 if (!str_restr && type->info.num.range) {
3006 str_restr = type->info.num.range->expr;
3007 }
3008 break;
3009 case LY_TYPE_STRING:
3010 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01003011 local_umin = __UINT64_C(0);
3012 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003013
3014 if (!str_restr && type->info.str.length) {
3015 str_restr = type->info.str.length->expr;
3016 }
3017 break;
3018 default:
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003019 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003020 }
3021
3022 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02003023 if (type->der) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003024 if (resolve_len_ran_interval(ctx, NULL, &type->der->type, &intv)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003025 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02003026 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003027 assert(!intv || (intv->kind == kind));
3028 }
3029
3030 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003031 /* we do not have any restriction, return superior ones */
3032 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003033 return EXIT_SUCCESS;
3034 }
3035
3036 /* adjust local min and max */
3037 if (intv) {
3038 tmp_intv = intv;
3039
3040 if (kind == 0) {
3041 local_umin = tmp_intv->value.uval.min;
3042 } else if (kind == 1) {
3043 local_smin = tmp_intv->value.sval.min;
3044 } else if (kind == 2) {
3045 local_fmin = tmp_intv->value.fval.min;
3046 }
3047
3048 while (tmp_intv->next) {
3049 tmp_intv = tmp_intv->next;
3050 }
3051
3052 if (kind == 0) {
3053 local_umax = tmp_intv->value.uval.max;
3054 } else if (kind == 1) {
3055 local_smax = tmp_intv->value.sval.max;
3056 } else if (kind == 2) {
3057 local_fmax = tmp_intv->value.fval.max;
3058 }
3059 }
3060
3061 /* finally parse our restriction */
3062 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003063 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003064 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003065 if (!tmp_local_intv) {
3066 assert(!local_intv);
3067 local_intv = malloc(sizeof *local_intv);
3068 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003069 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003070 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003071 tmp_local_intv = tmp_local_intv->next;
3072 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003073 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM(ctx), error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003074
3075 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003076 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003077 tmp_local_intv->next = NULL;
3078
3079 /* min */
3080 ptr = seg_ptr;
3081 while (isspace(ptr[0])) {
3082 ++ptr;
3083 }
3084 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3085 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02003086 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003087 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003088 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003089 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003090 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003091 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003092 goto error;
3093 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003094 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003095 } else if (!strncmp(ptr, "min", 3)) {
3096 if (kind == 0) {
3097 tmp_local_intv->value.uval.min = local_umin;
3098 } else if (kind == 1) {
3099 tmp_local_intv->value.sval.min = local_smin;
3100 } else if (kind == 2) {
3101 tmp_local_intv->value.fval.min = local_fmin;
3102 }
3103
3104 ptr += 3;
3105 } else if (!strncmp(ptr, "max", 3)) {
3106 if (kind == 0) {
3107 tmp_local_intv->value.uval.min = local_umax;
3108 } else if (kind == 1) {
3109 tmp_local_intv->value.sval.min = local_smax;
3110 } else if (kind == 2) {
3111 tmp_local_intv->value.fval.min = local_fmax;
3112 }
3113
3114 ptr += 3;
3115 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003116 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003117 }
3118
3119 while (isspace(ptr[0])) {
3120 ptr++;
3121 }
3122
3123 /* no interval or interval */
3124 if ((ptr[0] == '|') || !ptr[0]) {
3125 if (kind == 0) {
3126 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
3127 } else if (kind == 1) {
3128 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
3129 } else if (kind == 2) {
3130 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
3131 }
3132 } else if (!strncmp(ptr, "..", 2)) {
3133 /* skip ".." */
3134 ptr += 2;
3135 while (isspace(ptr[0])) {
3136 ++ptr;
3137 }
3138
3139 /* max */
3140 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
3141 if (kind == 0) {
Radek Krejci25894412017-07-11 10:53:16 +02003142 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003143 } else if (kind == 1) {
Radek Krejci25894412017-07-11 10:53:16 +02003144 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003145 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02003146 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003147 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
Michal Vaskod24dd012016-09-30 12:20:22 +02003148 goto error;
3149 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003150 }
3151 } else if (!strncmp(ptr, "max", 3)) {
3152 if (kind == 0) {
3153 tmp_local_intv->value.uval.max = local_umax;
3154 } else if (kind == 1) {
3155 tmp_local_intv->value.sval.max = local_smax;
3156 } else if (kind == 2) {
3157 tmp_local_intv->value.fval.max = local_fmax;
3158 }
3159 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003160 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003161 }
3162 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003163 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003164 }
3165
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003166 /* check min and max in correct order*/
3167 if (kind == 0) {
3168 /* current segment */
3169 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
3170 goto error;
3171 }
3172 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
3173 goto error;
3174 }
3175 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02003176 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003177 goto error;
3178 }
3179 } else if (kind == 1) {
3180 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
3181 goto error;
3182 }
3183 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
3184 goto error;
3185 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003186 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003187 goto error;
3188 }
3189 } else if (kind == 2) {
3190 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
3191 goto error;
3192 }
3193 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
3194 goto error;
3195 }
Pavol Vican69f62c92016-08-30 09:06:25 +02003196 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003197 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003198 goto error;
3199 }
3200 }
3201
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003202 /* next segment (next OR) */
3203 seg_ptr = strchr(seg_ptr, '|');
3204 if (!seg_ptr) {
3205 break;
3206 }
3207 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02003208 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003209 }
3210
3211 /* check local restrictions against superior ones */
3212 if (intv) {
3213 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02003214 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003215
3216 while (tmp_local_intv && tmp_intv) {
3217 /* reuse local variables */
3218 if (kind == 0) {
3219 local_umin = tmp_local_intv->value.uval.min;
3220 local_umax = tmp_local_intv->value.uval.max;
3221
3222 /* it must be in this interval */
3223 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
3224 /* this interval is covered, next one */
3225 if (local_umax <= tmp_intv->value.uval.max) {
3226 tmp_local_intv = tmp_local_intv->next;
3227 continue;
3228 /* ascending order of restrictions -> fail */
3229 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003230 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003231 }
3232 }
3233 } else if (kind == 1) {
3234 local_smin = tmp_local_intv->value.sval.min;
3235 local_smax = tmp_local_intv->value.sval.max;
3236
3237 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
3238 if (local_smax <= tmp_intv->value.sval.max) {
3239 tmp_local_intv = tmp_local_intv->next;
3240 continue;
3241 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003242 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003243 }
3244 }
3245 } else if (kind == 2) {
3246 local_fmin = tmp_local_intv->value.fval.min;
3247 local_fmax = tmp_local_intv->value.fval.max;
3248
Michal Vasko4d1f0482016-09-19 14:35:06 +02003249 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003250 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003251 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003252 tmp_local_intv = tmp_local_intv->next;
3253 continue;
3254 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003255 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003256 }
3257 }
3258 }
3259
3260 tmp_intv = tmp_intv->next;
3261 }
3262
3263 /* some interval left uncovered -> fail */
3264 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003265 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003266 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003267 }
3268
Michal Vaskoaeb51802016-04-11 10:58:47 +02003269 /* append the local intervals to all the intervals of the superior types, return it all */
3270 if (intv) {
3271 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3272 tmp_intv->next = local_intv;
3273 } else {
3274 intv = local_intv;
3275 }
3276 *ret = intv;
3277
3278 return EXIT_SUCCESS;
3279
3280error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003281 while (intv) {
3282 tmp_intv = intv->next;
3283 free(intv);
3284 intv = tmp_intv;
3285 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003286 while (local_intv) {
3287 tmp_local_intv = local_intv->next;
3288 free(local_intv);
3289 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003290 }
3291
Michal Vaskoaeb51802016-04-11 10:58:47 +02003292 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003293}
3294
Michal Vasko730dfdf2015-08-11 14:48:05 +02003295/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003296 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3297 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003298 *
3299 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003300 * @param[in] mod_name Typedef name module name.
3301 * @param[in] module Main module.
3302 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003303 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003304 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003305 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003306 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003307int
Michal Vasko1e62a092015-12-01 12:27:20 +01003308resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3309 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003310{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003311 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003312 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003313 int tpdf_size;
3314
Michal Vasko1dca6882015-10-22 14:29:42 +02003315 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003316 /* no prefix, try built-in types */
3317 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003318 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003319 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003320 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003321 }
3322 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003323 }
3324 }
3325 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003326 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003327 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003328 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003329 }
3330 }
3331
Michal Vasko1dca6882015-10-22 14:29:42 +02003332 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333 /* search in local typedefs */
3334 while (parent) {
3335 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003336 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003337 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3338 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003339 break;
3340
Radek Krejci76512572015-08-04 09:47:08 +02003341 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003342 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3343 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003344 break;
3345
Radek Krejci76512572015-08-04 09:47:08 +02003346 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003347 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3348 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003349 break;
3350
Radek Krejci76512572015-08-04 09:47:08 +02003351 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003352 case LYS_ACTION:
3353 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3354 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003355 break;
3356
Radek Krejci76512572015-08-04 09:47:08 +02003357 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003358 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3359 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003360 break;
3361
Radek Krejci76512572015-08-04 09:47:08 +02003362 case LYS_INPUT:
3363 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003364 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3365 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003366 break;
3367
3368 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003369 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003370 continue;
3371 }
3372
3373 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003374 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003375 match = &tpdf[i];
3376 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377 }
3378 }
3379
Michal Vaskodcf98e62016-05-05 17:53:53 +02003380 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 }
Radek Krejcic071c542016-01-27 14:57:51 +01003382 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003383 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02003384 module = lyp_get_module(module, NULL, 0, mod_name, 0, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003385 if (!module) {
3386 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 }
3388 }
3389
3390 /* search in top level typedefs */
3391 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003392 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003393 match = &module->tpdf[i];
3394 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003395 }
3396 }
3397
3398 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003399 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003400 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003401 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 +02003402 match = &module->inc[i].submodule->tpdf[j];
3403 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 }
3405 }
3406 }
3407
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003408 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003409
3410check_leafref:
3411 if (ret) {
3412 *ret = match;
3413 }
3414 if (match->type.base == LY_TYPE_LEAFREF) {
3415 while (!match->type.info.lref.path) {
3416 match = match->type.der;
3417 assert(match);
3418 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003419 }
3420 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003421}
3422
Michal Vasko1dca6882015-10-22 14:29:42 +02003423/**
3424 * @brief Check the default \p value of the \p type. Logs directly.
3425 *
3426 * @param[in] type Type definition to use.
3427 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003428 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003429 *
3430 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3431 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003432static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003433check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003434{
Radek Krejcibad2f172016-08-02 11:04:15 +02003435 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003436 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003437 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003438 char *s;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003439 int ret = EXIT_SUCCESS, r;
Michal Vasko53b7da02018-02-13 15:28:42 +01003440 struct ly_ctx *ctx = module->ctx;
Michal Vasko1dca6882015-10-22 14:29:42 +02003441
Radek Krejci51673202016-11-01 17:00:32 +01003442 assert(value);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003443 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003444
Radek Krejcic13db382016-08-16 10:52:42 +02003445 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003446 /* the type was not resolved yet, nothing to do for now */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003447 ret = EXIT_FAILURE;
3448 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003449 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003450 /* do not check defaults in not implemented module's data */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003451 goto cleanup;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003452 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003453 /* identityrefs are checked when instantiated in data instead of typedef,
3454 * but in typedef the value has to be modified to include the prefix */
3455 if (*value) {
3456 if (strchr(*value, ':')) {
3457 dflt = transform_schema2json(module, *value);
3458 } else {
3459 /* default prefix of the module where the typedef is defined */
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003460 if (asprintf(&s, "%s:%s", lys_main_module(module)->name, *value) == -1) {
3461 LOGMEM(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003462 ret = -1;
3463 goto cleanup;
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003464 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003465 dflt = lydict_insert_zc(ctx, s);
Radek Krejci9e6af732017-04-27 14:40:25 +02003466 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003467 lydict_remove(ctx, *value);
Radek Krejci9e6af732017-04-27 14:40:25 +02003468 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003469 dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003470 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003471 goto cleanup;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003472 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3473 /* leafref in typedef cannot be checked */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003474 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003475 }
3476
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003477 dflt = lydict_insert(ctx, *value, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003478 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003479 /* we do not have a new default value, so is there any to check even, in some base type? */
3480 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3481 if (base_tpdf->dflt) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003482 dflt = lydict_insert(ctx, base_tpdf->dflt, 0);
Michal Vasko478c4652016-07-21 12:55:01 +02003483 break;
3484 }
3485 }
3486
Radek Krejci51673202016-11-01 17:00:32 +01003487 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003488 /* no default value, nothing to check, all is well */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003489 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003490 }
3491
3492 /* 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)? */
3493 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003494 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003495 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003496 goto cleanup;
Radek Krejci9e6af732017-04-27 14:40:25 +02003497 } else {
3498 /* check the default value from typedef, but use also the typedef's module
3499 * due to possible searching in imported modules which is expected in
3500 * typedef's module instead of module where the typedef is used */
3501 module = base_tpdf->module;
3502 }
3503 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003504 case LY_TYPE_INST:
3505 case LY_TYPE_LEAFREF:
3506 case LY_TYPE_BOOL:
3507 case LY_TYPE_EMPTY:
3508 /* 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 +01003509 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003510 case LY_TYPE_BITS:
3511 /* the default value must match the restricted list of values, if the type was restricted */
3512 if (type->info.bits.count) {
3513 break;
3514 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003515 goto cleanup;
Radek Krejcibad2f172016-08-02 11:04:15 +02003516 case LY_TYPE_ENUM:
3517 /* the default value must match the restricted list of values, if the type was restricted */
3518 if (type->info.enums.count) {
3519 break;
3520 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003521 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003522 case LY_TYPE_DEC64:
3523 if (type->info.dec64.range) {
3524 break;
3525 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003526 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003527 case LY_TYPE_BINARY:
3528 if (type->info.binary.length) {
3529 break;
3530 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003531 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003532 case LY_TYPE_INT8:
3533 case LY_TYPE_INT16:
3534 case LY_TYPE_INT32:
3535 case LY_TYPE_INT64:
3536 case LY_TYPE_UINT8:
3537 case LY_TYPE_UINT16:
3538 case LY_TYPE_UINT32:
3539 case LY_TYPE_UINT64:
3540 if (type->info.num.range) {
3541 break;
3542 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003543 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003544 case LY_TYPE_STRING:
3545 if (type->info.str.length || type->info.str.patterns) {
3546 break;
3547 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003548 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003549 case LY_TYPE_UNION:
3550 /* way too much trouble learning whether we need to check the default again, so just do it */
3551 break;
3552 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01003553 LOGINT(ctx);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003554 ret = -1;
3555 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003556 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003557 } else if (type->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003558 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3559 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003560 ret = -1;
3561 goto cleanup;
Michal Vasko478c4652016-07-21 12:55:01 +02003562 }
3563
Michal Vasko1dca6882015-10-22 14:29:42 +02003564 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003565 memset(&node, 0, sizeof node);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003566 node.value_str = lydict_insert(ctx, dflt, 0);
Michal Vasko1dca6882015-10-22 14:29:42 +02003567 node.value_type = type->base;
Michal Vasko31a2d322018-01-12 13:36:12 +01003568
3569 if (tpdf) {
3570 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003571 if (!node.schema) {
3572 LOGMEM(ctx);
3573 ret = -1;
3574 goto cleanup;
3575 }
Michal Vaskod1bf7c42018-02-15 08:38:49 +01003576 r = asprintf((char **)&node.schema->name, "typedef-%s-default", ((struct lys_tpdf *)type->parent)->name);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003577 if (r == -1) {
3578 LOGMEM(ctx);
3579 ret = -1;
3580 goto cleanup;
3581 }
Michal Vasko31a2d322018-01-12 13:36:12 +01003582 node.schema->module = module;
3583 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
3584 } else {
3585 node.schema = (struct lys_node *)type->parent;
3586 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003587
Radek Krejci37b756f2016-01-18 10:15:03 +01003588 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003589 if (!type->info.lref.target) {
3590 ret = EXIT_FAILURE;
Michal Vasko00f28a72018-11-12 11:55:36 +01003591 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Default value \"%s\" cannot be checked in an unresolved leafref.",
3592 dflt);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003593 goto cleanup;
Michal Vasko1dca6882015-10-22 14:29:42 +02003594 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003595 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003596 if (!ret) {
3597 /* adopt possibly changed default value to its canonical form */
3598 if (*value) {
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003599 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003600 *value = dflt;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003601 dflt = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003602 }
3603 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003604 } else {
Michal Vasko35f46a82018-05-30 10:44:11 +02003605 if (!lyp_parse_value(type, &node.value_str, NULL, &node, NULL, module, 1, 1, 0)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003606 /* possible forward reference */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003607 ret = EXIT_FAILURE;
Radek Krejcibad2f172016-08-02 11:04:15 +02003608 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003609 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003610 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3611 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3612 /* we have refined bits/enums */
Michal Vasko53b7da02018-02-13 15:28:42 +01003613 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL,
Radek Krejcibad2f172016-08-02 11:04:15 +02003614 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003615 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003616 }
3617 }
Radek Krejci51673202016-11-01 17:00:32 +01003618 } else {
3619 /* success - adopt canonical form from the node into the default value */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003620 if (!ly_strequal(dflt, node.value_str, 1)) {
Radek Krejci51673202016-11-01 17:00:32 +01003621 /* this can happen only if we have non-inherited default value,
3622 * inherited default values are already in canonical form */
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003623 assert(ly_strequal(dflt, *value, 1));
3624
3625 lydict_remove(ctx, *value);
Radek Krejci51673202016-11-01 17:00:32 +01003626 *value = node.value_str;
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003627 node.value_str = NULL;
Radek Krejci51673202016-11-01 17:00:32 +01003628 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003629 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003630 }
3631
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003632cleanup:
Michal Vasko7ba37442018-11-06 08:59:27 +01003633 lyd_free_value(node.value, node.value_type, node.value_flags, type, NULL, NULL, NULL);
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003634 lydict_remove(ctx, node.value_str);
3635 if (tpdf && node.schema) {
Michal Vasko31a2d322018-01-12 13:36:12 +01003636 free((char *)node.schema->name);
3637 free(node.schema);
3638 }
Michal Vasko4b8eb8a2018-02-16 11:58:45 +01003639 lydict_remove(ctx, dflt);
Michal Vasko1dca6882015-10-22 14:29:42 +02003640
3641 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003642}
3643
Michal Vasko730dfdf2015-08-11 14:48:05 +02003644/**
3645 * @brief Check a key for mandatory attributes. Logs directly.
3646 *
3647 * @param[in] key The key to check.
3648 * @param[in] flags What flags to check.
3649 * @param[in] list The list of all the keys.
3650 * @param[in] index Index of the key in the key list.
3651 * @param[in] name The name of the keys.
3652 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003653 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003654 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003655 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003656static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003657check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003658{
Radek Krejciadb57612016-02-16 13:34:34 +01003659 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003660 char *dup = NULL;
3661 int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01003662 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003663
3664 /* existence */
3665 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003666 if (name[len] != '\0') {
3667 dup = strdup(name);
Michal Vasko53b7da02018-02-13 15:28:42 +01003668 LY_CHECK_ERR_RETURN(!dup, LOGMEM(ctx), -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003669 dup[len] = '\0';
3670 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003671 }
Michal Vasko53b7da02018-02-13 15:28:42 +01003672 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003673 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003674 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003675 }
3676
3677 /* uniqueness */
3678 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003679 if (key == list->keys[j]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003680 LOGVAL(ctx, LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003681 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003682 }
3683 }
3684
3685 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003686 if (key->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003687 LOGVAL(ctx, LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003688 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003689 }
3690
3691 /* type of the leaf is not built-in empty */
Radek Krejci13fde922018-05-16 10:45:58 +02003692 if (key->type.base == LY_TYPE_EMPTY && key->module->version < LYS_VERSION_1_1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003693 LOGVAL(ctx, LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003694 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003695 }
3696
3697 /* config attribute is the same as of the list */
Michal Vasko627016e2018-10-24 09:25:55 +02003698 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK)
3699 && ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003700 LOGVAL(ctx, LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003701 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003702 }
3703
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003704 /* key is not placed from augment */
3705 if (key->parent->nodetype == LYS_AUGMENT) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003706 LOGVAL(ctx, LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3707 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003708 return -1;
3709 }
3710
Radek Krejci3f21ada2016-08-01 13:34:31 +02003711 /* key is not when/if-feature -conditional */
3712 j = 0;
3713 if (key->when || (key->iffeature_size && (j = 1))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003714 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3715 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003716 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003717 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003718 }
3719
Michal Vasko0b85aa82016-03-07 14:37:43 +01003720 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003721}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003722
3723/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003724 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003725 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003726 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003727 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003728 *
3729 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3730 */
3731int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003732resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003733{
Radek Krejci581ce772015-11-10 17:22:40 +01003734 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003735 const struct lys_node *leaf = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01003736 struct ly_ctx *ctx = parent->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003737
Michal Vaskodc300b02017-04-07 14:09:20 +02003738 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003739 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003740 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003741 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003742 if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003743 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 +02003744 } else if (rc == -2) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003745 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003746 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003747 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003748 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01003749 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3750 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003751 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003752 }
Radek Krejci581ce772015-11-10 17:22:40 +01003753 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003754 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003755 if (leaf->nodetype != LYS_LEAF) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003756 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3757 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003758 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003759 }
3760
Radek Krejcicf509982015-12-15 09:22:44 +01003761 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003762 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3763 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003764 return -1;
3765 }
3766
Radek Krejcid09d1a52016-08-11 14:05:45 +02003767 /* check that all unique's targets are of the same config type */
3768 if (*trg_type) {
3769 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01003770 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3771 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003772 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3773 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3774 return -1;
3775 }
3776 } else {
3777 /* first unique */
3778 if (leaf->flags & LYS_CONFIG_W) {
3779 *trg_type = 1;
3780 } else {
3781 *trg_type = 2;
3782 }
3783 }
3784
Radek Krejcica7efb72016-01-18 13:06:01 +01003785 /* set leaf's unique flag */
3786 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3787
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003788 return EXIT_SUCCESS;
3789
3790error:
3791
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003792 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003793}
3794
Radek Krejci0c0086a2016-03-24 15:20:28 +01003795void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003796unres_data_del(struct unres_data *unres, uint32_t i)
3797{
3798 /* there are items after the one deleted */
3799 if (i+1 < unres->count) {
3800 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003801 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003802
3803 /* deleting the last item */
3804 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003805 free(unres->node);
3806 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003807 }
3808
3809 /* if there are no items after and it is not the last one, just move the counter */
3810 --unres->count;
3811}
3812
Michal Vasko0491ab32015-08-19 14:28:29 +02003813/**
3814 * @brief Resolve (find) a data node from a specific module. Does not log.
3815 *
3816 * @param[in] mod Module to search in.
3817 * @param[in] name Name of the data node.
3818 * @param[in] nam_len Length of the name.
3819 * @param[in] start Data node to start the search from.
3820 * @param[in,out] parents Resolved nodes. If there are some parents,
3821 * they are replaced (!!) with the resolvents.
3822 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003823 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003824 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003825static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003826resolve_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 +02003827{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003828 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003829 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003830 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003831
Michal Vasko23b61ec2015-08-19 11:19:50 +02003832 if (!parents->count) {
3833 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003834 parents->node = malloc(sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003835 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003836 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003837 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003838 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003839 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003840 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003841 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003842 continue;
3843 }
3844 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003845 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003846 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003847 && node->schema->name[nam_len] == '\0') {
3848 /* matching target */
3849 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003850 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003851 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003852 flag = 1;
3853 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003854 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003855 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003856 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01003857 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM(mod->ctx), EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003858 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003859 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003860 }
3861 }
3862 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003863
3864 if (!flag) {
3865 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003866 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003867 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003868 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003869 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003870 }
3871
Michal Vasko0491ab32015-08-19 14:28:29 +02003872 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003873}
3874
Michal Vaskoe27516a2016-10-10 17:55:31 +00003875static int
Michal Vasko1c007172017-03-10 10:20:44 +01003876resolve_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 +00003877{
3878 int dep1, dep2;
3879 const struct lys_node *node;
3880
3881 if (lys_parent(op_node)) {
3882 /* inner operation (notif/action) */
3883 if (abs_path) {
3884 return 1;
3885 } else {
3886 /* compare depth of both nodes */
3887 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3888 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3889 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3890 return 1;
3891 }
3892 }
3893 } else {
3894 /* top-level operation (notif/rpc) */
3895 if (op_node != first_node) {
3896 return 1;
3897 }
3898 }
3899
3900 return 0;
3901}
3902
Michal Vasko730dfdf2015-08-11 14:48:05 +02003903/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003904 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003905 *
Michal Vaskobb211122015-08-19 14:03:11 +02003906 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003907 * @param[in] context_node Predicate context node (where the predicate is placed).
3908 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003909 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003910 *
Michal Vasko184521f2015-09-24 13:14:26 +02003911 * @return 0 on forward reference, otherwise the number
3912 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003913 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003914 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003915static int
Michal Vasko1c007172017-03-10 10:20:44 +01003916resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3917 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003918{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003919 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003920 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003921 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003922 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3923 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01003924 struct ly_ctx *ctx = context_node->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02003925
3926 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003927 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003928 &pke_len, &has_predicate)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003929 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003930 return -parsed+i;
3931 }
3932 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003933 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003934
Michal Vasko58090902015-08-13 14:04:15 +02003935 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003936 if (sour_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003937 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003938 } else {
Michal Vaskoa50e60c2018-08-22 12:07:21 +02003939 trg_mod = lys_node_module(parent);
Michal Vasko36cbaa42015-12-14 13:15:48 +01003940 }
Michal Vaskobb520442017-05-23 10:55:18 +02003941 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003942 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003943 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003944 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003945 }
3946
3947 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003948 dest_parent_times = 0;
3949 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003950 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3951 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003952 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003953 return -parsed;
3954 }
3955 pke_parsed += i;
3956
Radek Krejciadb57612016-02-16 13:34:34 +01003957 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003958 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3959 && !((struct lys_node_augment *)dst_node->parent)->target) {
3960 /* we are in an unresolved augment, cannot evaluate */
Michal Vasko53b7da02018-02-13 15:28:42 +01003961 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
Michal Vasko3ba2d792017-07-10 15:14:43 +02003962 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3963 return 0;
3964 }
3965
Michal Vaskofbaead72016-10-07 10:54:48 +02003966 /* path is supposed to be evaluated in data tree, so we have to skip
3967 * all schema nodes that cannot be instantiated in data tree */
3968 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003969 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003970 dst_node = lys_parent(dst_node));
3971
Michal Vasko1f76a282015-08-04 16:16:53 +02003972 if (!dst_node) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003973 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003974 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003975 }
3976 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003977 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003978 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003979 if (dest_pref) {
Michal Vasko921eb6b2017-10-13 10:01:39 +02003980 trg_mod = lyp_get_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len, 0);
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003981 } else {
Michal Vaskoa50e60c2018-08-22 12:07:21 +02003982 trg_mod = lys_node_module(parent);
Michal Vasko36cbaa42015-12-14 13:15:48 +01003983 }
Michal Vaskobb520442017-05-23 10:55:18 +02003984 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 +02003985 if (rc) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02003986 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003987 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003988 }
3989
Michal Vaskoe27516a2016-10-10 17:55:31 +00003990 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003991 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003992 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003993 }
3994 first_iter = 0;
3995 }
3996
Michal Vasko1f76a282015-08-04 16:16:53 +02003997 if (pke_len == pke_parsed) {
3998 break;
3999 }
4000
Michal Vaskobb520442017-05-23 10:55:18 +02004001 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 +02004002 &dest_parent_times)) < 1) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02004003 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02004004 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02004005 return -parsed;
4006 }
4007 pke_parsed += i;
4008 }
4009
4010 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02004011 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskoaf8ec362018-03-28 09:08:09 +02004012 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref predicate", path - parsed);
Michal Vasko53b7da02018-02-13 15:28:42 +01004013 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02004014 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02004015 return -parsed;
4016 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004017 } while (has_predicate);
4018
4019 return parsed;
4020}
4021
Michal Vasko74083ec2018-06-15 10:00:12 +02004022static int
4023check_leafref_features(struct lys_type *type)
4024{
4025 struct lys_node *iter;
4026 struct ly_set *src_parents, *trg_parents, *features;
4027 struct lys_node_augment *aug;
4028 struct ly_ctx *ctx = ((struct lys_tpdf *)type->parent)->module->ctx;
4029 unsigned int i, j, size, x;
4030 int ret = EXIT_SUCCESS;
4031
4032 assert(type->parent);
4033
4034 src_parents = ly_set_new();
4035 trg_parents = ly_set_new();
4036 features = ly_set_new();
4037
4038 /* get parents chain of source (leafref) */
4039 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
4040 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4041 continue;
4042 }
4043 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4044 aug = (struct lys_node_augment *)iter->parent;
4045 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4046 /* unresolved augment, wait until it's resolved */
4047 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4048 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4049 ret = EXIT_FAILURE;
4050 goto cleanup;
4051 }
Michal Vaskod42871e2018-07-12 09:06:53 +02004052 /* also add this augment */
4053 ly_set_add(src_parents, aug, LY_SET_OPT_USEASLIST);
Michal Vasko74083ec2018-06-15 10:00:12 +02004054 }
4055 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
4056 }
4057 /* get parents chain of target */
4058 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
4059 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
4060 continue;
4061 }
4062 if (iter->parent && (iter->parent->nodetype == LYS_AUGMENT)) {
4063 aug = (struct lys_node_augment *)iter->parent;
4064 if ((aug->module->implemented && (aug->flags & LYS_NOTAPPLIED)) || !aug->target) {
4065 /* unresolved augment, wait until it's resolved */
4066 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, aug,
4067 "Cannot check leafref \"%s\" if-feature consistency because of an unresolved augment.", type->info.lref.path);
4068 ret = EXIT_FAILURE;
4069 goto cleanup;
4070 }
4071 }
4072 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
4073 }
4074
4075 /* compare the features used in if-feature statements in the rest of both
4076 * chains of parents. The set of features used for target must be a subset
4077 * of features used for the leafref. This is not a perfect, we should compare
4078 * the truth tables but it could require too much resources, so we simplify that */
4079 for (i = 0; i < src_parents->number; i++) {
4080 iter = src_parents->set.s[i]; /* shortcut */
4081 if (!iter->iffeature_size) {
4082 continue;
4083 }
4084 for (j = 0; j < iter->iffeature_size; j++) {
4085 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4086 for (; size; size--) {
4087 if (!iter->iffeature[j].features[size - 1]) {
4088 /* not yet resolved feature, postpone this check */
4089 ret = EXIT_FAILURE;
4090 goto cleanup;
4091 }
4092 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
4093 }
4094 }
4095 }
4096 x = features->number;
4097 for (i = 0; i < trg_parents->number; i++) {
4098 iter = trg_parents->set.s[i]; /* shortcut */
4099 if (!iter->iffeature_size) {
4100 continue;
4101 }
4102 for (j = 0; j < iter->iffeature_size; j++) {
4103 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
4104 for (; size; size--) {
4105 if (!iter->iffeature[j].features[size - 1]) {
4106 /* not yet resolved feature, postpone this check */
4107 ret = EXIT_FAILURE;
4108 goto cleanup;
4109 }
4110 if ((unsigned)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
4111 /* the feature is not present in features set of target's parents chain */
4112 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
4113 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
4114 "Leafref is not conditional based on \"%s\" feature as its target.",
4115 iter->iffeature[j].features[size - 1]->name);
4116 ret = -1;
4117 goto cleanup;
4118 }
4119 }
4120 }
4121 }
4122
4123cleanup:
4124 ly_set_free(features);
4125 ly_set_free(src_parents);
4126 ly_set_free(trg_parents);
4127
4128 return ret;
4129}
4130
Michal Vasko730dfdf2015-08-11 14:48:05 +02004131/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004132 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004133 *
Michal Vaskobb211122015-08-19 14:03:11 +02004134 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004135 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004136 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004137 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004138 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004139 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004140static int
Michal Vasko74083ec2018-06-15 10:00:12 +02004141resolve_schema_leafref(struct lys_type *type, struct lys_node *parent, struct unres_schema *unres)
Michal Vasko1f76a282015-08-04 16:16:53 +02004142{
Michal Vaskocb45f472018-02-12 10:47:42 +01004143 const struct lys_node *node, *op_node = NULL, *tmp_parent;
Michal Vaskobb520442017-05-23 10:55:18 +02004144 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02004145 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02004146 const char *id, *prefix, *name;
4147 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskocb45f472018-02-12 10:47:42 +01004148 int i, first_iter;
Michal Vasko53b7da02018-02-13 15:28:42 +01004149 struct ly_ctx *ctx = parent->module->ctx;
Michal Vasko1f76a282015-08-04 16:16:53 +02004150
Michal Vasko74083ec2018-06-15 10:00:12 +02004151 if (!type->info.lref.target) {
4152 first_iter = 1;
4153 parent_times = 0;
4154 id = type->info.lref.path;
Michal Vasko1f76a282015-08-04 16:16:53 +02004155
Michal Vasko74083ec2018-06-15 10:00:12 +02004156 /* find operation schema we are in */
4157 for (op_node = lys_parent(parent);
4158 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
4159 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02004160
Michal Vasko74083ec2018-06-15 10:00:12 +02004161 cur_module = lys_node_module(parent);
4162 do {
4163 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
4164 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vaskobb520442017-05-23 10:55:18 +02004165 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004166 }
4167 id += i;
Michal Vasko74083ec2018-06-15 10:00:12 +02004168
4169 /* get the current module */
4170 tmp_mod = prefix ? lyp_get_module(cur_module, NULL, 0, prefix, pref_len, 0) : cur_module;
4171 if (!tmp_mod) {
4172 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4173 return EXIT_FAILURE;
4174 }
4175 last_aug = NULL;
4176
4177 if (first_iter) {
4178 if (parent_times == -1) {
4179 /* use module data */
4180 node = NULL;
4181
4182 } else if (parent_times > 0) {
4183 /* we are looking for the right parent */
4184 for (i = 0, node = parent; i < parent_times; i++) {
4185 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
4186 && !((struct lys_node_augment *)node->parent)->target) {
4187 /* we are in an unresolved augment, cannot evaluate */
4188 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, node->parent,
4189 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", type->info.lref.path);
4190 return EXIT_FAILURE;
4191 }
4192
4193 /* path is supposed to be evaluated in data tree, so we have to skip
4194 * all schema nodes that cannot be instantiated in data tree */
4195 for (node = lys_parent(node);
4196 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
4197 node = lys_parent(node));
4198
4199 if (!node) {
4200 if (i == parent_times - 1) {
4201 /* top-level */
4202 break;
4203 }
4204
4205 /* higher than top-level */
4206 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4207 return EXIT_FAILURE;
4208 }
4209 }
4210 } else {
4211 LOGINT(ctx);
4212 return -1;
4213 }
4214 }
4215
4216 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
4217 * - useless to search for that in augments) */
4218 if (!tmp_mod->implemented && node) {
4219 get_next_augment:
4220 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
4221 }
4222
4223 tmp_parent = (last_aug ? (struct lys_node *)last_aug : node);
4224 node = NULL;
4225 while ((node = lys_getnext(node, tmp_parent, tmp_mod, LYS_GETNEXT_NOSTATECHECK))) {
4226 if (lys_node_module(node) != lys_main_module(tmp_mod)) {
4227 continue;
4228 }
4229 if (strncmp(node->name, name, nam_len) || node->name[nam_len]) {
4230 continue;
4231 }
4232 /* match */
4233 break;
4234 }
4235 if (!node) {
4236 if (last_aug) {
4237 /* restore the correct augment target */
4238 node = last_aug->target;
4239 goto get_next_augment;
4240 }
4241 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4242 return EXIT_FAILURE;
4243 }
4244
4245 if (first_iter) {
4246 /* set external dependency flag, we can decide based on the first found node */
4247 if (op_node && parent_times &&
4248 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
4249 parent->flags |= LYS_LEAFREF_DEP;
4250 }
4251 first_iter = 0;
4252 }
4253
4254 if (has_predicate) {
4255 /* we have predicate, so the current result must be list */
4256 if (node->nodetype != LYS_LIST) {
4257 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4258 return -1;
4259 }
4260
4261 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
4262 if (!i) {
4263 return EXIT_FAILURE;
4264 } else if (i < 0) {
4265 return -1;
4266 }
4267 id += i;
4268 has_predicate = 0;
4269 }
4270 } while (id[0]);
4271
4272 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
4273 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
4274 LOGVAL(ctx, LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", type->info.lref.path);
4275 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", type->info.lref.path);
4276 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004277 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004278
Michal Vasko74083ec2018-06-15 10:00:12 +02004279 /* check status */
4280 if (lyp_check_status(parent->flags, parent->module, parent->name,
4281 node->flags, node->module, node->name, node)) {
4282 return -1;
4283 }
4284
4285 /* assign */
4286 type->info.lref.target = (struct lys_node_leaf *)node;
Radek Krejcib1c12512015-08-11 11:22:04 +02004287 }
4288
Michal Vasko74083ec2018-06-15 10:00:12 +02004289 /* as the last thing traverse this leafref and make targets on the path implemented */
4290 if (lys_node_module(parent)->implemented) {
4291 /* make all the modules in the path implemented */
4292 for (node = (struct lys_node *)type->info.lref.target; node; node = lys_parent(node)) {
4293 if (!lys_node_module(node)->implemented) {
4294 lys_node_module(node)->implemented = 1;
4295 if (unres_schema_add_node(lys_node_module(node), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4296 return -1;
4297 }
4298 }
4299 }
4300
4301 /* store the backlink from leafref target */
4302 if (lys_leaf_add_leafref_target(type->info.lref.target, (struct lys_node *)type->parent)) {
4303 return -1;
4304 }
Radek Krejcicf509982015-12-15 09:22:44 +01004305 }
4306
Michal Vasko74083ec2018-06-15 10:00:12 +02004307 /* check if leafref and its target are under common if-features */
4308 return check_leafref_features(type);
Michal Vasko1f76a282015-08-04 16:16:53 +02004309}
4310
Michal Vasko730dfdf2015-08-11 14:48:05 +02004311/**
Michal Vasko718ecdd2017-10-03 14:12:39 +02004312 * @brief Compare 2 data node values.
4313 *
4314 * Comparison performed on canonical forms, the first value
4315 * is first transformed into canonical form.
4316 *
4317 * @param[in] node Leaf/leaf-list with these values.
4318 * @param[in] noncan_val Non-canonical value.
4319 * @param[in] noncan_val_len Length of \p noncal_val.
4320 * @param[in] can_val Canonical value.
4321 * @return 1 if equal, 0 if not, -1 on error (logged).
4322 */
4323static int
4324valequal(struct lys_node *node, const char *noncan_val, int noncan_val_len, const char *can_val)
4325{
4326 int ret;
4327 struct lyd_node_leaf_list leaf;
4328 struct lys_node_leaf *sleaf = (struct lys_node_leaf*)node;
4329
4330 /* dummy leaf */
4331 memset(&leaf, 0, sizeof leaf);
4332 leaf.value_str = lydict_insert(node->module->ctx, noncan_val, noncan_val_len);
4333
4334repeat:
4335 leaf.value_type = sleaf->type.base;
4336 leaf.schema = node;
4337
4338 if (leaf.value_type == LY_TYPE_LEAFREF) {
4339 if (!sleaf->type.info.lref.target) {
4340 /* it should either be unresolved leafref (leaf.value_type are ORed flags) or it will be resolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01004341 LOGINT(node->module->ctx);
Michal Vasko718ecdd2017-10-03 14:12:39 +02004342 ret = -1;
4343 goto finish;
4344 }
4345 sleaf = sleaf->type.info.lref.target;
4346 goto repeat;
4347 } else {
Michal Vasko35f46a82018-05-30 10:44:11 +02004348 if (!lyp_parse_value(&sleaf->type, &leaf.value_str, NULL, &leaf, NULL, NULL, 0, 0, 0)) {
Michal Vasko718ecdd2017-10-03 14:12:39 +02004349 ret = -1;
4350 goto finish;
4351 }
4352 }
4353
4354 if (!strcmp(leaf.value_str, can_val)) {
4355 ret = 1;
4356 } else {
4357 ret = 0;
4358 }
4359
4360finish:
4361 lydict_remove(node->module->ctx, leaf.value_str);
4362 return ret;
4363}
4364
4365/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004366 * @brief Resolve instance-identifier predicate in JSON data format.
4367 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004368 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02004369 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02004370 * @param[in] pred Predicate to use.
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004371 * @param[in,out] node Node matching the restriction without
4372 * the predicate. If it does not satisfy the predicate,
4373 * it is set to NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004374 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004375 * @return Number of characters successfully parsed,
4376 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004377 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004378static int
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004379resolve_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 +02004380{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004381 /* ... /node[key=value] ... */
4382 struct lyd_node_leaf_list *key;
4383 struct lys_node_leaf **list_keys = NULL;
Michal Vaskoab8adcd2017-10-02 13:32:24 +02004384 struct lys_node_list *slist = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004385 const char *model, *name, *value;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004386 int mod_len, nam_len, val_len, i, has_predicate, parsed;
Michal Vasko53b7da02018-02-13 15:28:42 +01004387 struct ly_ctx *ctx = prev_mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004388
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004389 assert(pred && node && *node);
Michal Vasko1f2cc332015-08-19 11:18:32 +02004390
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004391 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004392 do {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004393 if ((i = parse_predicate(pred + parsed, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
4394 return -parsed + i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004395 }
4396 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004397
Michal Vasko88850b72017-10-02 13:13:21 +02004398 if (!(*node)) {
4399 /* just parse it all */
4400 continue;
4401 }
4402
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004403 /* target */
4404 if (name[0] == '.') {
4405 /* leaf-list value */
4406 if ((*node)->schema->nodetype != LYS_LEAFLIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004407 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects leaf-list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004408 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4409 parsed = -1;
4410 goto cleanup;
4411 }
4412
4413 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004414 if (!valequal((*node)->schema, value, val_len, ((struct lyd_node_leaf_list *)*node)->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004415 *node = NULL;
4416 goto cleanup;
4417 }
4418
4419 } else if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004420 assert(!value);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004421
4422 /* keyless list position */
4423 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004424 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004425 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4426 parsed = -1;
4427 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004428 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004429
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004430 if (((struct lys_node_list *)(*node)->schema)->keys) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004431 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 +02004432 (*node)->schema->name);
4433 parsed = -1;
4434 goto cleanup;
4435 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004436
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004437 /* check the index */
4438 if (atoi(name) != cur_idx) {
4439 *node = NULL;
4440 goto cleanup;
4441 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004442
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004443 } else {
4444 /* list key value */
4445 if ((*node)->schema->nodetype != LYS_LIST) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004446 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list, but have %s \"%s\".",
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004447 strnodetype((*node)->schema->nodetype), (*node)->schema->name);
4448 parsed = -1;
4449 goto cleanup;
4450 }
4451 slist = (struct lys_node_list *)(*node)->schema;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004452
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004453 /* prepare key array */
4454 if (!list_keys) {
4455 list_keys = malloc(slist->keys_size * sizeof *list_keys);
Michal Vasko53b7da02018-02-13 15:28:42 +01004456 LY_CHECK_ERR_RETURN(!list_keys, LOGMEM(ctx), -1);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004457 for (i = 0; i < slist->keys_size; ++i) {
4458 list_keys[i] = slist->keys[i];
Michal Vaskob2f40be2016-09-08 16:03:48 +02004459 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004460 }
4461
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004462 /* find the schema key leaf */
4463 for (i = 0; i < slist->keys_size; ++i) {
4464 if (list_keys[i] && !strncmp(list_keys[i]->name, name, nam_len) && !list_keys[i]->name[nam_len]) {
4465 break;
4466 }
4467 }
4468 if (i == slist->keys_size) {
4469 /* this list has no such key */
Michal Vasko53b7da02018-02-13 15:28:42 +01004470 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier expects list with the key \"%.*s\","
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004471 " but list \"%s\" does not define it.", nam_len, name, slist->name);
4472 parsed = -1;
4473 goto cleanup;
4474 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004475
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004476 /* check module */
4477 if (model) {
4478 if (strncmp(list_keys[i]->module->name, model, mod_len) || list_keys[i]->module->name[mod_len]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004479 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 +02004480 list_keys[i]->name, model, mod_len, list_keys[i]->module->name);
4481 parsed = -1;
4482 goto cleanup;
4483 }
4484 } else {
4485 if (list_keys[i]->module != prev_mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004486 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 +02004487 list_keys[i]->name, prev_mod->name, list_keys[i]->module->name);
4488 parsed = -1;
4489 goto cleanup;
4490 }
4491 }
4492
4493 /* find the actual data key */
4494 for (key = (struct lyd_node_leaf_list *)(*node)->child; key; key = (struct lyd_node_leaf_list *)key->next) {
4495 if (key->schema == (struct lys_node *)list_keys[i]) {
4496 break;
4497 }
4498 }
4499 if (!key) {
4500 /* list instance is missing a key? definitely should not happen */
Michal Vasko53b7da02018-02-13 15:28:42 +01004501 LOGINT(ctx);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004502 parsed = -1;
4503 goto cleanup;
4504 }
4505
4506 /* check the value */
Michal Vasko718ecdd2017-10-03 14:12:39 +02004507 if (!valequal(key->schema, value, val_len, key->value_str)) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004508 *node = NULL;
Michal Vasko88850b72017-10-02 13:13:21 +02004509 /* we still want to parse the whole predicate */
4510 continue;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004511 }
4512
4513 /* everything is fine, mark this key as resolved */
4514 list_keys[i] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004515 }
4516 } while (has_predicate);
4517
Michal Vaskob2f40be2016-09-08 16:03:48 +02004518 /* check that all list keys were specified */
Michal Vasko88850b72017-10-02 13:13:21 +02004519 if (*node && list_keys) {
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004520 for (i = 0; i < slist->keys_size; ++i) {
4521 if (list_keys[i]) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004522 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 +02004523 parsed = -1;
4524 goto cleanup;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004525 }
4526 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004527 }
4528
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02004529cleanup:
4530 free(list_keys);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004531 return parsed;
4532}
4533
Michal Vasko895c11f2018-03-12 11:35:58 +01004534static int
4535check_xpath(struct lys_node *node, int check_place)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004536{
Michal Vasko0b963112017-08-11 12:45:36 +02004537 struct lys_node *parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004538 struct lyxp_set set;
Michal Vasko895c11f2018-03-12 11:35:58 +01004539 enum int_log_opts prev_ilo;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004540
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004541 if (check_place) {
4542 parent = node;
4543 while (parent) {
4544 if (parent->nodetype == LYS_GROUPING) {
4545 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004546 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004547 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004548 if (parent->nodetype == LYS_AUGMENT) {
4549 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004550 /* unresolved augment, skip for now (will be checked later) */
4551 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004552 } else {
4553 parent = ((struct lys_node_augment *)parent)->target;
4554 continue;
4555 }
4556 }
4557 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004558 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004559 }
4560
Michal Vasko895c11f2018-03-12 11:35:58 +01004561 memset(&set, 0, sizeof set);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004562
Michal Vasko895c11f2018-03-12 11:35:58 +01004563 /* produce just warnings */
4564 ly_ilo_change(NULL, ILO_ERR2WRN, &prev_ilo, NULL);
4565 lyxp_node_atomize(node, &set, 1);
4566 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
4567
4568 if (set.val.snodes) {
4569 free(set.val.snodes);
4570 }
4571 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004572}
4573
Radek Krejcif71f48f2016-10-25 16:37:24 +02004574static int
4575check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4576{
Radek Krejcidce5f972017-09-12 15:47:49 +02004577 unsigned int i;
Radek Krejcif71f48f2016-10-25 16:37:24 +02004578
4579 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004580 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4581 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004582 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 +02004583 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4584 return -1;
4585 }
4586 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4587 * of leafref resolving (lys_leaf_add_leafref_target()) */
4588 } else if (type->base == LY_TYPE_UNION) {
4589 for (i = 0; i < type->info.uni.count; i++) {
4590 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4591 return -1;
4592 }
4593 }
4594 }
4595 return 0;
4596}
4597
Michal Vasko9e635ac2016-10-17 11:44:09 +02004598/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004599 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004600 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004601 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004602 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004603 * @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 +02004604 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004605 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004606 *
4607 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004608 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004609int
4610inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004611{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004612 struct lys_node_leaf *leaf;
Michal Vasko53b7da02018-02-13 15:28:42 +01004613 struct ly_ctx *ctx;
4614
4615 if (!node) {
4616 return 0;
4617 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004618
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004619 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Michal Vasko53b7da02018-02-13 15:28:42 +01004620 ctx = node->module->ctx;
4621
Radek Krejci1d82ef62015-08-07 14:44:40 +02004622 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004623 if (clear) {
4624 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004625 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004626 } else {
4627 if (node->flags & LYS_CONFIG_SET) {
4628 /* skip nodes with an explicit config value */
4629 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004630 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4631 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004632 return -1;
4633 }
4634 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004635 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004636
4637 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4638 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4639 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004640 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4641 && !((struct lys_node_list *)node)->keys_size) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004642 LOGVAL(ctx, LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
Michal Vaskoe022a562016-09-27 14:24:15 +02004643 return -1;
4644 }
4645 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004646 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004647 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004648 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004649 return -1;
4650 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004651 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4652 leaf = (struct lys_node_leaf *)node;
4653 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004654 return -1;
4655 }
4656 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004657 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004658
4659 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004660}
4661
Michal Vasko730dfdf2015-08-11 14:48:05 +02004662/**
Michal Vasko7178e692016-02-12 15:58:05 +01004663 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004664 *
Michal Vaskobb211122015-08-19 14:03:11 +02004665 * @param[in] aug Augment to use.
Michal Vasko97234262018-02-01 09:53:01 +01004666 * @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 +01004667 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004668 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004669 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004670 */
Michal Vasko7178e692016-02-12 15:58:05 +01004671static int
Michal Vasko97234262018-02-01 09:53:01 +01004672resolve_augment(struct lys_node_augment *aug, struct lys_node *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004673{
Michal Vasko44ab1462017-05-18 13:18:36 +02004674 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004675 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004676 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004677 struct ly_set *set;
Michal Vasko53b7da02018-02-13 15:28:42 +01004678 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004679
Michal Vasko2ef7db62017-06-12 09:24:02 +02004680 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004681 mod = lys_main_module(aug->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01004682 ctx = mod->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004683
Michal Vaskobb520442017-05-23 10:55:18 +02004684 /* set it as not applied for now */
4685 aug->flags |= LYS_NOTAPPLIED;
4686
Michal Vasko2ef7db62017-06-12 09:24:02 +02004687 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004688 if (!aug->target) {
Michal Vasko2ef7db62017-06-12 09:24:02 +02004689 /* resolve target node */
Michal Vasko97234262018-02-01 09:53:01 +01004690 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 +02004691 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004692 LOGVAL(ctx, LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004693 return -1;
4694 }
Michal Vasko50576712017-07-28 12:28:33 +02004695 if (!set) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004696 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
Michal Vasko2ef7db62017-06-12 09:24:02 +02004697 return EXIT_FAILURE;
4698 }
Michal Vasko50576712017-07-28 12:28:33 +02004699 aug->target = set->set.s[0];
4700 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004701 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004702
Michal Vasko74083ec2018-06-15 10:00:12 +02004703 /* make this module implemented if the target module is (if the target is in an unimplemented module,
4704 * it is fine because when we will be making that module implemented, its augment will be applied
4705 * and that augment target module made implemented, recursively) */
4706 if (mod->implemented && !lys_node_module(aug->target)->implemented) {
4707 lys_node_module(aug->target)->implemented = 1;
4708 if (unres_schema_add_node(lys_node_module(aug->target), unres, NULL, UNRES_MOD_IMPLEMENT, NULL) == -1) {
4709 return -1;
4710 }
4711 }
4712
Michal Vaskod58d5962016-03-02 14:29:41 +01004713 /* check for mandatory nodes - if the target node is in another module
4714 * the added nodes cannot be mandatory
4715 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004716 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4717 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004718 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004719 }
4720
Michal Vasko07e89ef2016-03-03 13:28:57 +01004721 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004722 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004723 LY_TREE_FOR(aug->child, sub) {
4724 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4725 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004726 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4727 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004728 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004729 return -1;
4730 }
4731 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004732 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004733 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004734 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004735 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4736 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004737 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004738 return -1;
4739 }
4740 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004741 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004742 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004743 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004744 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4745 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004746 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004747 return -1;
4748 }
4749 }
4750 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01004751 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
4752 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 +01004753 return -1;
4754 }
4755
Radek Krejcic071c542016-01-27 14:57:51 +01004756 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004757 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004758 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004759 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004760 }
4761 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004762
Michal Vasko44ab1462017-05-18 13:18:36 +02004763 if (!aug->child) {
4764 /* empty augment, nothing to connect, but it is techincally applied */
Michal Vasko53b7da02018-02-13 15:28:42 +01004765 LOGWRN(ctx, "Augment \"%s\" without children.", aug->target_name);
Michal Vasko44ab1462017-05-18 13:18:36 +02004766 aug->flags &= ~LYS_NOTAPPLIED;
Radek Krejciaa6b2a12017-10-26 15:52:39 +02004767 } else if ((aug->parent || mod->implemented) && apply_aug(aug, unres)) {
4768 /* we try to connect the augment only in case the module is implemented or
4769 * the augment applies on the used grouping, anyway we failed here */
Michal Vasko44ab1462017-05-18 13:18:36 +02004770 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004771 }
4772
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004773 return EXIT_SUCCESS;
4774}
4775
Radek Krejcie534c132016-11-23 13:32:31 +01004776static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004777resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004778{
4779 enum LY_VLOG_ELEM vlog_type;
4780 void *vlog_node;
4781 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004782 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004783 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004784 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004785 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004786 struct lys_ext_instance *tmp_ext;
Michal Vasko53b7da02018-02-13 15:28:42 +01004787 struct ly_ctx *ctx = NULL;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004788 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004789
4790 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004791 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004792 vlog_node = info->parent;
4793 vlog_type = LY_VLOG_LYS;
4794 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004795 case LYEXT_PAR_MODULE:
4796 case LYEXT_PAR_IMPORT:
4797 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004798 vlog_node = NULL;
4799 vlog_type = LY_VLOG_LYS;
4800 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004801 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004802 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004803 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004804 break;
4805 }
4806
4807 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004808 /* YIN */
4809
Radek Krejcie534c132016-11-23 13:32:31 +01004810 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004811 mod = lyp_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004812 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004813 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004814 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004815 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004816 ctx = mod->ctx;
Radek Krejcie534c132016-11-23 13:32:31 +01004817
4818 /* find the extension definition */
4819 e = NULL;
4820 for (i = 0; i < mod->extensions_size; i++) {
4821 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4822 e = &mod->extensions[i];
4823 break;
4824 }
4825 }
4826 /* try submodules */
4827 for (j = 0; !e && j < mod->inc_size; j++) {
4828 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4829 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4830 e = &mod->inc[j].submodule->extensions[i];
4831 break;
4832 }
4833 }
4834 }
4835 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004836 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004837 return EXIT_FAILURE;
4838 }
4839
4840 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004841
Radek Krejci72b35992017-01-04 16:27:44 +01004842 if (e->plugin && e->plugin->check_position) {
4843 /* common part - we have plugin with position checking function, use it first */
4844 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4845 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004846 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004847 return -1;
4848 }
4849 }
4850
Radek Krejci8d6b7422017-02-03 14:42:13 +01004851 /* extension type-specific part - allocation */
4852 if (e->plugin) {
4853 etype = e->plugin->type;
4854 } else {
4855 /* default type */
4856 etype = LYEXT_FLAG;
4857 }
4858 switch (etype) {
4859 case LYEXT_FLAG:
4860 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4861 break;
4862 case LYEXT_COMPLEX:
4863 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4864 break;
4865 case LYEXT_ERR:
4866 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004867 LOGINT(ctx);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004868 return -1;
4869 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004870 LY_CHECK_ERR_RETURN(!*ext, LOGMEM(ctx), -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004871
4872 /* common part for all extension types */
4873 (*ext)->def = e;
4874 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004875 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004876 (*ext)->insubstmt = info->substmt;
4877 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004878 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01004879 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004880
PavolVicand86b0d62017-09-01 11:01:39 +02004881 if (e->argument) {
4882 if (!(e->flags & LYS_YINELEM)) {
4883 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4884 if (!(*ext)->arg_value) {
PavolVicane7a1fc62018-02-19 16:50:27 +01004885 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
PavolVicand86b0d62017-09-01 11:01:39 +02004886 return -1;
4887 }
4888
4889 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4890 } else {
4891 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4892 if (ly_strequal(yin->name, e->argument, 1)) {
4893 (*ext)->arg_value = lydict_insert(mod->ctx, yin->content, 0);
4894 lyxml_free(mod->ctx, yin);
4895 break;
4896 }
4897 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004898 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004899 }
4900
PavolVican92f23622017-12-12 13:35:56 +01004901 if ((*ext)->flags & LYEXT_OPT_VALID &&
4902 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01004903 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004904 }
4905
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004906 (*ext)->nodetype = LYS_EXT;
4907 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004908
Radek Krejci8d6b7422017-02-03 14:42:13 +01004909 /* extension type-specific part - parsing content */
4910 switch (etype) {
4911 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004912 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4913 if (!yin->ns) {
4914 /* garbage */
4915 lyxml_free(mod->ctx, yin);
4916 continue;
4917 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4918 /* standard YANG statements are not expected here */
Michal Vasko53b7da02018-02-13 15:28:42 +01004919 LOGVAL(ctx, LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejci72b35992017-01-04 16:27:44 +01004920 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004921 } else if (yin->ns == info->data.yin->ns &&
4922 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004923 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004924 if ((*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004925 LOGVAL(ctx, LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004926 return -1;
4927 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004928 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004929 yin->content = NULL;
4930 lyxml_free(mod->ctx, yin);
4931 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004932 /* extension instance */
4933 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4934 LYEXT_SUBSTMT_SELF, 0, unres)) {
4935 return -1;
4936 }
Radek Krejci72b35992017-01-04 16:27:44 +01004937
Radek Krejci72b35992017-01-04 16:27:44 +01004938 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004939 }
Radek Krejci72b35992017-01-04 16:27:44 +01004940 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004941 break;
4942 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004943 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004944 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4945 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004946 return -1;
4947 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004948 break;
4949 default:
4950 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004951 }
Radek Krejci72b35992017-01-04 16:27:44 +01004952
4953 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4954
Radek Krejcie534c132016-11-23 13:32:31 +01004955 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004956 /* YANG */
4957
PavolVicanc1807262017-01-31 18:00:27 +01004958 ext_prefix = (char *)(*ext)->def;
4959 tmp = strchr(ext_prefix, ':');
4960 if (!tmp) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004961 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004962 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004963 }
4964 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004965
PavolVicanc1807262017-01-31 18:00:27 +01004966 /* get the module where the extension is supposed to be defined */
Michal Vasko921eb6b2017-10-13 10:01:39 +02004967 mod = lyp_get_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0, 0);
PavolVicanc1807262017-01-31 18:00:27 +01004968 if (!mod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004969 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004970 return EXIT_FAILURE;
4971 }
Michal Vasko53b7da02018-02-13 15:28:42 +01004972 ctx = mod->ctx;
PavolVicanc1807262017-01-31 18:00:27 +01004973
4974 /* find the extension definition */
4975 e = NULL;
4976 for (i = 0; i < mod->extensions_size; i++) {
4977 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4978 e = &mod->extensions[i];
4979 break;
4980 }
4981 }
4982 /* try submodules */
4983 for (j = 0; !e && j < mod->inc_size; j++) {
4984 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4985 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4986 e = &mod->inc[j].submodule->extensions[i];
4987 break;
4988 }
4989 }
4990 }
4991 if (!e) {
Michal Vasko53b7da02018-02-13 15:28:42 +01004992 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVicanc1807262017-01-31 18:00:27 +01004993 return EXIT_FAILURE;
4994 }
4995
PavolVicanfcc98762017-09-01 15:51:39 +02004996 (*ext)->flags &= ~LYEXT_OPT_YANG;
4997 (*ext)->def = NULL;
4998
PavolVicanc1807262017-01-31 18:00:27 +01004999 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
5000
5001 if (e->plugin && e->plugin->check_position) {
5002 /* common part - we have plugin with position checking function, use it first */
5003 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
5004 /* extension is not allowed here */
Michal Vasko53b7da02018-02-13 15:28:42 +01005005 LOGVAL(ctx, LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01005006 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01005007 }
5008 }
5009
PavolVican22e88682017-02-14 22:38:18 +01005010 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01005011 (*ext)->def = e;
5012 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01005013 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican92f23622017-12-12 13:35:56 +01005014 (*ext)->flags |= e->plugin ? e->plugin->flags : 0;
PavolVican22e88682017-02-14 22:38:18 +01005015
PavolVicanb0d84102017-02-15 16:32:42 +01005016 if (e->argument && !(*ext)->arg_value) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005017 LOGVAL(ctx, LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
PavolVicanb0d84102017-02-15 16:32:42 +01005018 goto error;
5019 }
5020
PavolVican92f23622017-12-12 13:35:56 +01005021 if ((*ext)->flags & LYEXT_OPT_VALID &&
5022 (info->parent_type == LYEXT_PAR_NODE || info->parent_type == LYEXT_PAR_TPDF)) {
Michal Vasko1bdfd432018-03-09 09:30:19 +01005023 ((struct lys_node *)info->parent)->flags |= LYS_VALID_EXT;
PavolVican92f23622017-12-12 13:35:56 +01005024 }
5025
Radek Krejci7f1d47e2017-04-12 15:29:02 +02005026 (*ext)->module = info->mod;
5027 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02005028
PavolVican22e88682017-02-14 22:38:18 +01005029 /* extension type-specific part */
5030 if (e->plugin) {
5031 etype = e->plugin->type;
5032 } else {
5033 /* default type */
5034 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01005035 }
PavolVican22e88682017-02-14 22:38:18 +01005036 switch (etype) {
5037 case LYEXT_FLAG:
5038 /* nothing change */
5039 break;
5040 case LYEXT_COMPLEX:
5041 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Michal Vasko53b7da02018-02-13 15:28:42 +01005042 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM(ctx), error);
PavolVican22e88682017-02-14 22:38:18 +01005043 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
5044 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01005045 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01005046 if (info->data.yang) {
5047 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01005048 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
5049 (struct lys_ext_instance_complex*)(*ext))) {
5050 goto error;
5051 }
5052 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
5053 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01005054 goto error;
5055 }
PavolVicana3876672017-02-21 15:49:51 +01005056 }
5057 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
5058 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01005059 }
PavolVican22e88682017-02-14 22:38:18 +01005060 break;
5061 case LYEXT_ERR:
5062 /* we never should be here */
Michal Vasko53b7da02018-02-13 15:28:42 +01005063 LOGINT(ctx);
PavolVican22e88682017-02-14 22:38:18 +01005064 goto error;
5065 }
5066
PavolVican22e88682017-02-14 22:38:18 +01005067 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
5068 goto error;
5069 }
5070 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01005071 }
5072
5073 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01005074error:
5075 free(ext_prefix);
5076 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01005077}
5078
Michal Vasko730dfdf2015-08-11 14:48:05 +02005079/**
Pavol Vican855ca622016-09-05 13:07:54 +02005080 * @brief Resolve (find) choice default case. Does not log.
5081 *
5082 * @param[in] choic Choice to use.
5083 * @param[in] dflt Name of the default case.
5084 *
5085 * @return Pointer to the default node or NULL.
5086 */
5087static struct lys_node *
5088resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
5089{
5090 struct lys_node *child, *ret;
5091
5092 LY_TREE_FOR(choic->child, child) {
5093 if (child->nodetype == LYS_USES) {
5094 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
5095 if (ret) {
5096 return ret;
5097 }
5098 }
5099
5100 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02005101 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02005102 return child;
5103 }
5104 }
5105
5106 return NULL;
5107}
5108
5109/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02005110 * @brief Resolve uses, apply augments, refines. Logs directly.
5111 *
Michal Vaskobb211122015-08-19 14:03:11 +02005112 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005113 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005114 *
Michal Vaskodef0db12015-10-07 13:22:48 +02005115 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005116 */
Michal Vasko184521f2015-09-24 13:14:26 +02005117static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005118resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005119{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005120 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02005121 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02005122 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02005123 struct lys_node_leaflist *llist;
5124 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02005125 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005126 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02005127 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005128 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005129 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02005130 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005131
Michal Vasko71e1aa82015-08-12 12:17:51 +02005132 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01005133
Radek Krejci93def382017-05-24 15:33:48 +02005134 /* check that the grouping is resolved (no unresolved uses inside) */
5135 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02005136
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005137 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01005138 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01005139 if (node_aux->nodetype & LYS_GROUPING) {
5140 /* do not instantiate groupings from groupings */
5141 continue;
5142 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01005143 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01005144 if (!node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005145 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
5146 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005147 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005148 }
Pavol Vican55abd332016-07-12 15:54:49 +02005149 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01005150 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 +02005151 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005152 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02005153 }
5154 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005155 }
Michal Vaskoe022a562016-09-27 14:24:15 +02005156
Michal Vaskodef0db12015-10-07 13:22:48 +02005157 /* we managed to copy the grouping, the rest must be possible to resolve */
5158
Pavol Vican855ca622016-09-05 13:07:54 +02005159 if (uses->refine_size) {
5160 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Michal Vasko53b7da02018-02-13 15:28:42 +01005161 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005162 }
5163
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005164 /* apply refines */
5165 for (i = 0; i < uses->refine_size; i++) {
5166 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01005167 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
5168 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02005169 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01005170 if (rc || !node) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005171 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005172 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005173 }
5174
Radek Krejci1d82ef62015-08-07 14:44:40 +02005175 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005176 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
5177 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02005178 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005179 }
Pavol Vican855ca622016-09-05 13:07:54 +02005180 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005181
5182 /* description on any nodetype */
5183 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005184 lydict_remove(ctx, node->dsc);
5185 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005186 }
5187
5188 /* reference on any nodetype */
5189 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005190 lydict_remove(ctx, node->ref);
5191 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005192 }
5193
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005194 /* config on any nodetype,
5195 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
5196 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005197 node->flags &= ~LYS_CONFIG_MASK;
5198 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005199 }
5200
5201 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02005202 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005203 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005204 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02005205 leaf = (struct lys_node_leaf *)node;
5206
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005207 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02005208 lydict_remove(ctx, leaf->dflt);
5209 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
5210
5211 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01005212 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
5213 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005214 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005215 }
Radek Krejci200bf712016-08-16 17:11:04 +02005216 } else if (node->nodetype == LYS_LEAFLIST) {
5217 /* leaf-list */
5218 llist = (struct lys_node_leaflist *)node;
5219
5220 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01005221 for (j = 0; j < llist->dflt_size; j++) {
5222 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02005223 }
5224 free(llist->dflt);
5225
5226 /* copy the default set from refine */
Radek Krejciaa1303c2017-05-31 13:57:37 +02005227 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
Michal Vasko53b7da02018-02-13 15:28:42 +01005228 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM(ctx), fail);
Radek Krejci200bf712016-08-16 17:11:04 +02005229 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01005230 for (j = 0; j < llist->dflt_size; j++) {
5231 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02005232 }
5233
5234 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01005235 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01005236 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01005237 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02005238 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02005239 }
5240 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005241 }
5242 }
5243
5244 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02005245 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01005246 /* remove current value */
5247 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005248
Radek Krejcibf285832017-01-26 16:05:41 +01005249 /* set new value */
5250 node->flags |= (rfn->flags & LYS_MAND_MASK);
5251
Pavol Vican855ca622016-09-05 13:07:54 +02005252 if (rfn->flags & LYS_MAND_TRUE) {
5253 /* check if node has default value */
5254 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005255 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005256 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005257 goto fail;
5258 }
5259 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005260 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses,
Radek Krejcibdcaf242017-04-19 10:29:47 +02005261 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005262 goto fail;
5263 }
5264 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005265 }
5266
5267 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005268 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
5269 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
5270 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005271 }
5272
5273 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02005274 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005275 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005276 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005277 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005278 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005279 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005280 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02005281 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005282 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005283 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005284 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02005285 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02005286 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005287 }
5288 }
5289
5290 /* must in leaf, leaf-list, list, container or anyxml */
5291 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005292 switch (node->nodetype) {
5293 case LYS_LEAF:
5294 old_size = &((struct lys_node_leaf *)node)->must_size;
5295 old_must = &((struct lys_node_leaf *)node)->must;
5296 break;
5297 case LYS_LEAFLIST:
5298 old_size = &((struct lys_node_leaflist *)node)->must_size;
5299 old_must = &((struct lys_node_leaflist *)node)->must;
5300 break;
5301 case LYS_LIST:
5302 old_size = &((struct lys_node_list *)node)->must_size;
5303 old_must = &((struct lys_node_list *)node)->must;
5304 break;
5305 case LYS_CONTAINER:
5306 old_size = &((struct lys_node_container *)node)->must_size;
5307 old_must = &((struct lys_node_container *)node)->must;
5308 break;
5309 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005310 case LYS_ANYDATA:
5311 old_size = &((struct lys_node_anydata *)node)->must_size;
5312 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005313 break;
5314 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01005315 LOGINT(ctx);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005316 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005317 }
5318
5319 size = *old_size + rfn->must_size;
5320 must = realloc(*old_must, size * sizeof *rfn->must);
Michal Vasko53b7da02018-02-13 15:28:42 +01005321 LY_CHECK_ERR_GOTO(!must, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005322 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01005323 must[j].ext_size = rfn->must[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005324 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 +02005325 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02005326 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
5327 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
5328 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
5329 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
5330 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Radek Krejcicfcd8a52017-09-04 13:19:57 +02005331 must[j].flags = rfn->must[k].flags;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005332 }
5333
Michal Vaskoef2fdc82015-09-24 09:54:42 +02005334 *old_must = must;
5335 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02005336
5337 /* check XPath dependencies again */
5338 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
5339 goto fail;
5340 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005341 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02005342
5343 /* if-feature in leaf, leaf-list, list, container or anyxml */
5344 if (rfn->iffeature_size) {
5345 old_size = &node->iffeature_size;
5346 old_iff = &node->iffeature;
5347
5348 size = *old_size + rfn->iffeature_size;
5349 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Michal Vasko53b7da02018-02-13 15:28:42 +01005350 LY_CHECK_ERR_GOTO(!iff, LOGMEM(ctx), fail);
Radek Krejci3a3b2002017-09-13 16:39:02 +02005351 *old_iff = iff;
5352
Pavol Vican855ca622016-09-05 13:07:54 +02005353 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
5354 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005355 if (usize1) {
5356 /* there is something to duplicate */
5357 /* duplicate compiled expression */
5358 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
5359 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Michal Vasko53b7da02018-02-13 15:28:42 +01005360 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005361 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005362
5363 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02005364 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Michal Vasko53b7da02018-02-13 15:28:42 +01005365 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM(ctx), fail);
Pavol Vican855ca622016-09-05 13:07:54 +02005366 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005367
Radek Krejci3a3b2002017-09-13 16:39:02 +02005368 /* duplicate extensions */
5369 iff[j].ext_size = rfn->iffeature[k].ext_size;
Michal Vasko17e8ba32018-02-15 10:58:56 +01005370 lys_ext_dup(ctx, rfn->module, rfn->iffeature[k].ext, rfn->iffeature[k].ext_size,
Radek Krejci3a3b2002017-09-13 16:39:02 +02005371 &rfn->iffeature[k], LYEXT_PAR_IFFEATURE, &iff[j].ext, 0, unres);
5372 }
5373 (*old_size)++;
5374 }
5375 assert(*old_size == size);
Radek Krejci363bd4a2016-07-29 14:30:20 +02005376 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005377 }
5378
5379 /* apply augments */
5380 for (i = 0; i < uses->augment_size; i++) {
Michal Vasko97234262018-02-01 09:53:01 +01005381 rc = resolve_augment(&uses->augment[i], (struct lys_node *)uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005382 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02005383 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005384 }
5385 }
5386
Pavol Vican855ca622016-09-05 13:07:54 +02005387 /* check refines */
5388 for (i = 0; i < uses->refine_size; i++) {
5389 node = refine_nodes[i];
5390 rfn = &uses->refine[i];
5391
5392 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02005393 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02005394 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01005395 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02005396 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
5397 (rfn->flags & LYS_CONFIG_W)) {
5398 /* setting config true under config false is prohibited */
Michal Vasko53b7da02018-02-13 15:28:42 +01005399 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5400 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005401 "changing config from 'false' to 'true' is prohibited while "
5402 "the target's parent is still config 'false'.");
5403 goto fail;
5404 }
5405
5406 /* inherit config change to the target children */
5407 LY_TREE_DFS_BEGIN(node->child, next, iter) {
5408 if (rfn->flags & LYS_CONFIG_W) {
5409 if (iter->flags & LYS_CONFIG_SET) {
5410 /* config is set explicitely, go to next sibling */
5411 next = NULL;
5412 goto nextsibling;
5413 }
5414 } else { /* LYS_CONFIG_R */
5415 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
5416 /* error - we would have config data under status data */
Michal Vasko53b7da02018-02-13 15:28:42 +01005417 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
5418 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005419 "changing config from 'true' to 'false' is prohibited while the target "
5420 "has still a children with explicit config 'true'.");
5421 goto fail;
5422 }
5423 }
5424 /* change config */
5425 iter->flags &= ~LYS_CONFIG_MASK;
5426 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
5427
5428 /* select next iter - modified LY_TREE_DFS_END */
5429 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5430 next = NULL;
5431 } else {
5432 next = iter->child;
5433 }
5434nextsibling:
5435 if (!next) {
5436 /* try siblings */
5437 next = iter->next;
5438 }
5439 while (!next) {
5440 /* parent is already processed, go to its sibling */
5441 iter = lys_parent(iter);
5442
5443 /* no siblings, go back through parents */
5444 if (iter == node) {
5445 /* we are done, no next element to process */
5446 break;
5447 }
5448 next = iter->next;
5449 }
5450 }
5451 }
5452
5453 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005454 if (rfn->dflt_size) {
5455 if (node->nodetype == LYS_CHOICE) {
5456 /* choice */
5457 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5458 rfn->dflt[0]);
5459 if (!((struct lys_node_choice *)node)->dflt) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005460 LOGVAL(ctx, LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005461 goto fail;
5462 }
5463 if (lyp_check_mandatory_choice(node)) {
5464 goto fail;
5465 }
Pavol Vican855ca622016-09-05 13:07:54 +02005466 }
5467 }
5468
5469 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02005470 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005471 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005472 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5473 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005474 goto fail;
5475 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02005476 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02005477 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005478 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5479 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02005480 goto fail;
5481 }
5482 }
5483
5484 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005485 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005486 if (node->nodetype == LYS_LEAFLIST) {
5487 llist = (struct lys_node_leaflist *)node;
5488 if (llist->dflt_size && llist->min) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005489 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
5490 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02005491 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5492 goto fail;
5493 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005494 } else if (node->nodetype == LYS_LEAF) {
5495 leaf = (struct lys_node_leaf *)node;
5496 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005497 LOGVAL(ctx, LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
5498 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005499 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5500 goto fail;
5501 }
Pavol Vican855ca622016-09-05 13:07:54 +02005502 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005503
Pavol Vican855ca622016-09-05 13:07:54 +02005504 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005505 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005506 for (parent = node->parent;
5507 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5508 parent = parent->parent) {
5509 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5510 /* stop also on presence containers */
5511 break;
5512 }
5513 }
5514 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5515 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5516 if (lyp_check_mandatory_choice(parent)) {
5517 goto fail;
5518 }
5519 }
5520 }
5521 }
5522 free(refine_nodes);
5523
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005524 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005525
5526fail:
5527 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5528 lys_node_free(iter, NULL, 0);
5529 }
Pavol Vican855ca622016-09-05 13:07:54 +02005530 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005531 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005532}
5533
Radek Krejci83a4bac2017-02-07 15:53:04 +01005534void
5535resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005536{
5537 int i;
5538
5539 assert(der && base);
5540
Radek Krejci018f1f52016-08-03 16:01:20 +02005541 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005542 /* create a set for backlinks if it does not exist */
5543 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005544 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005545 /* store backlink */
5546 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005547
Radek Krejci85a54be2016-10-20 12:39:56 +02005548 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005549 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005550 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005551 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005552}
5553
Michal Vasko730dfdf2015-08-11 14:48:05 +02005554/**
5555 * @brief Resolve base identity recursively. Does not log.
5556 *
5557 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005558 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005559 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005560 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005561 *
Radek Krejci219fa612016-08-15 10:36:51 +02005562 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005563 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005564static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005565resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005566 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005567{
Michal Vaskof02e3742015-08-05 16:27:02 +02005568 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005569 struct lys_ident *base = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01005570 struct ly_ctx *ctx = module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005571
Radek Krejcicf509982015-12-15 09:22:44 +01005572 assert(ret);
5573
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005574 /* search module */
5575 for (i = 0; i < module->ident_size; i++) {
5576 if (!strcmp(basename, module->ident[i].name)) {
5577
5578 if (!ident) {
5579 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005580 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005581 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005582 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005583 }
5584
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005585 base = &module->ident[i];
5586 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005587 }
5588 }
5589
5590 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005591 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5592 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5593 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005594
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005595 if (!ident) {
5596 *ret = &module->inc[j].submodule->ident[i];
5597 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005598 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005599
5600 base = &module->inc[j].submodule->ident[i];
5601 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005602 }
5603 }
5604 }
5605
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005606matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005607 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005608 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005609 /* is it already completely resolved? */
5610 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005611 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005612 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5613
5614 /* simple check for circular reference,
5615 * the complete check is done as a side effect of using only completely
5616 * resolved identities (previous check of unres content) */
5617 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005618 LOGVAL(ctx, LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5619 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005620 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005621 }
5622
Radek Krejci06f64ed2016-08-15 11:07:44 +02005623 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005624 }
5625 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005626
Radek Krejcibabbff82016-02-19 13:31:37 +01005627 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005628 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005629 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005630 }
5631
Radek Krejci219fa612016-08-15 10:36:51 +02005632 /* base not found (maybe a forward reference) */
5633 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005634}
5635
Michal Vasko730dfdf2015-08-11 14:48:05 +02005636/**
5637 * @brief Resolve base identity. Logs directly.
5638 *
5639 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005640 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005641 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005642 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005643 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005644 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005645 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005646 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005647static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005648resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005649 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005650{
5651 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005652 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005653 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005654 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005655 struct lys_module *mod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005656 struct ly_ctx *ctx = module->ctx;
Radek Krejcicf509982015-12-15 09:22:44 +01005657
5658 assert((ident && !type) || (!ident && type));
5659
5660 if (!type) {
5661 /* have ident to resolve */
5662 ret = &target;
5663 flags = ident->flags;
5664 mod = ident->module;
5665 } else {
5666 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005667 ++type->info.ident.count;
5668 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 +01005669 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM(ctx), -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005670
5671 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005672 flags = type->parent->flags;
5673 mod = type->parent->module;
5674 }
Michal Vaskof2006002016-04-21 16:28:15 +02005675 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005676
5677 /* search for the base identity */
5678 name = strchr(basename, ':');
5679 if (name) {
5680 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005681 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005682 name++;
5683
Michal Vasko2d851a92015-10-20 16:16:36 +02005684 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005685 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005686 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005687 }
5688 } else {
5689 name = basename;
5690 }
5691
Radek Krejcic071c542016-01-27 14:57:51 +01005692 /* get module where to search */
Michal Vasko921eb6b2017-10-13 10:01:39 +02005693 module = lyp_get_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len, 0);
Radek Krejcic071c542016-01-27 14:57:51 +01005694 if (!module) {
5695 /* identity refers unknown data model */
Michal Vasko53b7da02018-02-13 15:28:42 +01005696 LOGVAL(ctx, LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005697 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005698 }
5699
Radek Krejcic071c542016-01-27 14:57:51 +01005700 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005701 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5702 if (!rc) {
5703 assert(*ret);
5704
5705 /* check status */
5706 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5707 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5708 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005709 } else if (ident) {
5710 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005711 if (lys_main_module(mod)->implemented) {
5712 /* in case of the implemented identity, maintain backlinks to it
5713 * from the base identities to make it available when resolving
5714 * data with the identity values (not implemented identity is not
5715 * allowed as an identityref value). */
5716 resolve_identity_backlink_update(ident, *ret);
5717 }
Radek Krejci219fa612016-08-15 10:36:51 +02005718 }
5719 } else if (rc == EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005720 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005721 if (type) {
5722 --type->info.ident.count;
5723 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005724 }
5725
Radek Krejci219fa612016-08-15 10:36:51 +02005726 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005727}
5728
Radek Krejci9e6af732017-04-27 14:40:25 +02005729/*
5730 * 1 - true (der is derived from base)
5731 * 0 - false (der is not derived from base)
5732 */
5733static int
5734search_base_identity(struct lys_ident *der, struct lys_ident *base)
5735{
5736 int i;
5737
5738 if (der == base) {
5739 return 1;
5740 } else {
5741 for(i = 0; i < der->base_size; i++) {
5742 if (search_base_identity(der->base[i], base) == 1) {
5743 return 1;
5744 }
5745 }
5746 }
5747
5748 return 0;
5749}
5750
Michal Vasko730dfdf2015-08-11 14:48:05 +02005751/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005752 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005753 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005754 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005755 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005756 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005757 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005758 *
5759 * @return Pointer to the identity resolvent, NULL on error.
5760 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005761struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005762resolve_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 +02005763{
Radek Krejci9e6af732017-04-27 14:40:25 +02005764 const char *mod_name, *name;
Michal Vasko08767f72017-10-06 14:38:08 +02005765 char *str;
Radek Krejcidce5f972017-09-12 15:47:49 +02005766 int mod_name_len, nam_len, rc;
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005767 int need_implemented = 0;
Michal Vasko08767f72017-10-06 14:38:08 +02005768 unsigned int i, j;
Michal Vaskof2d43962016-09-02 11:10:16 +02005769 struct lys_ident *der, *cur;
Andrew Langefeld8f50a2d2018-05-23 17:16:12 -05005770 struct lys_module *imod = NULL, *m, *tmod;
Michal Vasko53b7da02018-02-13 15:28:42 +01005771 struct ly_ctx *ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005772
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005773 assert(type && ident_name && mod);
Michal Vasko53b7da02018-02-13 15:28:42 +01005774 ctx = mod->ctx;
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005775
Michal Vaskof2d43962016-09-02 11:10:16 +02005776 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005777 return NULL;
5778 }
5779
Michal Vasko50576712017-07-28 12:28:33 +02005780 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005781 if (rc < 1) {
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005782 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005783 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005784 } else if (rc < (signed)strlen(ident_name)) {
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005785 LOGVAL(ctx, LYE_INCHAR, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005786 return NULL;
5787 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005788
5789 m = lys_main_module(mod); /* shortcut */
5790 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5791 /* identity is defined in the same module as node */
5792 imod = m;
5793 } else if (dflt) {
5794 /* solving identityref in default definition in schema -
5795 * find the identity's module in the imported modules list to have a correct revision */
5796 for (i = 0; i < mod->imp_size; i++) {
5797 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5798 imod = mod->imp[i].module;
5799 break;
5800 }
5801 }
Andrew Langefeld8f50a2d2018-05-23 17:16:12 -05005802
5803 /* We may need to pull it from the module that the typedef came from */
5804 if (!imod && type && type->der) {
5805 tmod = type->der->module;
5806 for (i = 0; i < tmod->imp_size; i++) {
5807 if (!strncmp(mod_name, tmod->imp[i].module->name, mod_name_len) && !tmod->imp[i].module->name[mod_name_len]) {
5808 imod = tmod->imp[i].module;
5809 break;
5810 }
5811 }
5812 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005813 } else {
Michal Vasko08767f72017-10-06 14:38:08 +02005814 /* solving identityref in data - get the module from the context */
5815 for (i = 0; i < (unsigned)mod->ctx->models.used; ++i) {
5816 imod = mod->ctx->models.list[i];
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005817 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
Radek Krejci9e6af732017-04-27 14:40:25 +02005818 break;
5819 }
Michal Vasko08767f72017-10-06 14:38:08 +02005820 imod = NULL;
5821 }
Radek Krejci5ba05102017-10-26 15:02:52 +02005822 if (!imod && mod->ctx->models.parsing_sub_modules_count) {
5823 /* we are currently parsing some module and checking XPath or a default value,
5824 * so take this module into account */
5825 for (i = 0; i < mod->ctx->models.parsing_sub_modules_count; i++) {
5826 imod = mod->ctx->models.parsing_sub_modules[i];
5827 if (imod->type) {
5828 /* skip submodules */
5829 continue;
5830 }
5831 if (!strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5832 break;
5833 }
5834 imod = NULL;
5835 }
5836 }
Michal Vasko08767f72017-10-06 14:38:08 +02005837 }
5838
Michal Vasko53b7da02018-02-13 15:28:42 +01005839 if (!dflt && (!imod || !imod->implemented) && ctx->data_clb) {
Michal Vasko08767f72017-10-06 14:38:08 +02005840 /* the needed module was not found, but it may have been expected so call the data callback */
5841 if (imod) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005842 ctx->data_clb(ctx, imod->name, imod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
Radek Krejci58523dc2017-10-27 10:00:17 +02005843 } else if (mod_name) {
Michal Vasko08767f72017-10-06 14:38:08 +02005844 str = strndup(mod_name, mod_name_len);
Michal Vasko53b7da02018-02-13 15:28:42 +01005845 imod = (struct lys_module *)ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
Michal Vasko08767f72017-10-06 14:38:08 +02005846 free(str);
Radek Krejci9e6af732017-04-27 14:40:25 +02005847 }
5848 }
5849 if (!imod) {
5850 goto fail;
5851 }
5852
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005853 if (m != imod || lys_main_module(type->parent->module) != mod) {
Michal Vasko08767f72017-10-06 14:38:08 +02005854 /* the type is not referencing the same schema,
Radek Krejci9e6af732017-04-27 14:40:25 +02005855 * THEN, we may need to make the module with the identity implemented, but only if it really
5856 * contains the identity */
5857 if (!imod->implemented) {
5858 cur = NULL;
5859 /* get the identity in the module */
5860 for (i = 0; i < imod->ident_size; i++) {
5861 if (!strcmp(name, imod->ident[i].name)) {
5862 cur = &imod->ident[i];
5863 break;
5864 }
5865 }
5866 if (!cur) {
5867 /* go through includes */
5868 for (j = 0; j < imod->inc_size; j++) {
5869 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5870 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5871 cur = &imod->inc[j].submodule->ident[i];
5872 break;
5873 }
5874 }
5875 }
5876 if (!cur) {
5877 goto fail;
5878 }
5879 }
5880
5881 /* check that identity is derived from one of the type's base */
5882 while (type->der) {
5883 for (i = 0; i < type->info.ident.count; i++) {
5884 if (search_base_identity(cur, type->info.ident.ref[i])) {
5885 /* cur's base matches the type's base */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005886 need_implemented = 1;
Radek Krejci9e6af732017-04-27 14:40:25 +02005887 goto match;
5888 }
5889 }
5890 type = &type->der->type;
5891 }
5892 /* matching base not found */
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005893 LOGVAL(ctx, LYE_SPEC, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "Identity used as identityref value is not implemented.");
Radek Krejci9e6af732017-04-27 14:40:25 +02005894 goto fail;
5895 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005896 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005897
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005898 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005899 while (type->der) {
5900 for (i = 0; i < type->info.ident.count; ++i) {
5901 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005902
Radek Krejci85a54be2016-10-20 12:39:56 +02005903 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005904 /* there are some derived identities */
Michal Vasko08767f72017-10-06 14:38:08 +02005905 for (j = 0; j < cur->der->number; j++) {
5906 der = (struct lys_ident *)cur->der->set.g[j]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005907 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005908 /* we have match */
5909 cur = der;
5910 goto match;
5911 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005912 }
5913 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005914 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005915 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005916 }
5917
Radek Krejci9e6af732017-04-27 14:40:25 +02005918fail:
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005919 LOGVAL(ctx, LYE_INRESOLV, node ? LY_VLOG_LYD : LY_VLOG_NONE, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005920 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005921
5922match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005923 for (i = 0; i < cur->iffeature_size; i++) {
5924 if (!resolve_iffeature(&cur->iffeature[i])) {
Michal Vaskoae4b7d32018-07-13 12:21:01 +02005925 if (node) {
5926 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
5927 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005928 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 +02005929 return NULL;
5930 }
5931 }
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005932 if (need_implemented) {
5933 if (dflt) {
Michal Vasko0f437062018-06-08 15:52:39 +02005934 /* later try to make the module implemented */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005935 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5936 imod->name, cur->name, mod->name);
Michal Vasko0f437062018-06-08 15:52:39 +02005937 /* to be more effective we should use UNRES_MOD_IMPLEMENT but that would require changing prototype of
5938 * several functions with little gain */
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005939 if (lys_set_implemented(imod)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005940 LOGERR(ctx, ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005941 imod->name, cur->name);
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005942 goto fail;
5943 }
5944 } else {
5945 /* just say that it was found, but in a non-implemented module */
Michal Vasko53b7da02018-02-13 15:28:42 +01005946 LOGVAL(ctx, LYE_SPEC, LY_VLOG_NONE, NULL, "Identity found, but in a non-implemented module \"%s\".",
Michal Vasko3f3c6a82017-10-03 10:23:23 +02005947 lys_main_module(cur->module)->name);
Radek Krejci9e6af732017-04-27 14:40:25 +02005948 goto fail;
5949 }
5950 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005951 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005952}
5953
Michal Vasko730dfdf2015-08-11 14:48:05 +02005954/**
Michal Vaskobb211122015-08-19 14:03:11 +02005955 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005956 *
Michal Vaskobb211122015-08-19 14:03:11 +02005957 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005958 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005959 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005960 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005961 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005962static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005963resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005964{
Radek Krejci93def382017-05-24 15:33:48 +02005965 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005966 struct lys_node *par_grp;
Michal Vasko53b7da02018-02-13 15:28:42 +01005967 struct ly_ctx *ctx = uses->module->ctx;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005968
Radek Krejci6ff885d2017-01-03 14:06:22 +01005969 /* 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 +02005970 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5971 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5972 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005973 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoa9792722018-06-28 09:01:02 +02005974 if (par_grp && ly_strequal(par_grp->name, uses->name, 1)) {
5975 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
5976 return -1;
5977 }
Michal Vaskoe91afce2015-08-12 12:21:00 +02005978
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005979 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005980 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5981 if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005982 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005983 return -1;
5984 } else if (rc > 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005985 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005986 return -1;
5987 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005988 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005989 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01005990 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02005991 return -1;
5992 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005993 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005994 }
Michal Vasko53b7da02018-02-13 15:28:42 +01005995 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005996 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005997 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005998 }
5999
Radek Krejci93def382017-05-24 15:33:48 +02006000 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006001 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02006002 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006003 LOGERR(ctx, LY_EINT, "Too many unresolved items (uses) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006004 return -1;
6005 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006006 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02006007 } else {
6008 /* instantiate grouping only when it is completely resolved */
6009 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02006010 }
Michal Vaskoa9792722018-06-28 09:01:02 +02006011 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006012 return EXIT_FAILURE;
6013 }
6014
Radek Krejci48464ed2016-03-17 15:44:09 +01006015 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006016 if (!rc) {
6017 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01006018 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02006019 assert(((struct lys_node_grp *)par_grp)->unres_count);
6020 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01006021 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006022 }
Radek Krejcicf509982015-12-15 09:22:44 +01006023
6024 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01006025 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01006026 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01006027 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01006028 return -1;
6029 }
6030
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006031 return EXIT_SUCCESS;
6032 }
6033
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006034 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006035}
6036
Michal Vasko730dfdf2015-08-11 14:48:05 +02006037/**
Michal Vasko9957e592015-08-17 15:04:09 +02006038 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006039 *
Michal Vaskobb211122015-08-19 14:03:11 +02006040 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006041 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006042 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006043 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02006044 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006045static int
Radek Krejci48464ed2016-03-17 15:44:09 +01006046resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006047{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006048 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01006049 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02006050 char *s = NULL;
Michal Vasko53b7da02018-02-13 15:28:42 +01006051 struct ly_ctx *ctx = list->module->ctx;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006052
6053 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02006054 assert(keys_str);
6055
Radek Krejci5c08a992016-11-02 13:30:04 +01006056 if (!list->child) {
6057 /* no child, possible forward reference */
Michal Vasko53b7da02018-02-13 15:28:42 +01006058 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
Radek Krejci5c08a992016-11-02 13:30:04 +01006059 return EXIT_FAILURE;
6060 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006061 /* get the key name */
6062 if ((value = strpbrk(keys_str, " \t\n"))) {
6063 len = value - keys_str;
6064 while (isspace(value[0])) {
6065 value++;
6066 }
6067 } else {
6068 len = strlen(keys_str);
6069 }
6070
Michal Vaskobb520442017-05-23 10:55:18 +02006071 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
6072 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006073 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006074 LOGVAL(ctx, LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02006075 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006076 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006077
Radek Krejci48464ed2016-03-17 15:44:09 +01006078 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006079 /* check_key logs */
6080 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006081 }
6082
Radek Krejcicf509982015-12-15 09:22:44 +01006083 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01006084 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01006085 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
6086 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01006087 return -1;
6088 }
6089
Radek Krejcia98048c2017-05-24 16:35:48 +02006090 /* default value - is ignored, keep it but print a warning */
6091 if (list->keys[i]->dflt) {
6092 /* log is not hidden only in case this resolving fails and in such a case
6093 * we cannot get here
6094 */
Michal Vasko53b7da02018-02-13 15:28:42 +01006095 assert(log_opt == ILO_STORE);
6096 log_opt = ILO_LOG;
6097 LOGWRN(ctx, "Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
Michal Vasko395b0a02018-01-22 09:36:20 +01006098 list->keys[i]->name, s = lys_path((struct lys_node*)list, LYS_PATH_FIRST_PREFIX));
Michal Vasko53b7da02018-02-13 15:28:42 +01006099 log_opt = ILO_STORE;
Radek Krejcia98048c2017-05-24 16:35:48 +02006100 free(s);
6101 }
6102
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006103 /* prepare for next iteration */
6104 while (value && isspace(value[0])) {
6105 value++;
6106 }
6107 keys_str = value;
6108 }
6109
Michal Vaskof02e3742015-08-05 16:27:02 +02006110 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006111}
6112
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006113/**
Michal Vaskobf19d252015-10-08 15:39:17 +02006114 * @brief Resolve (check) all must conditions of \p node.
6115 * Logs directly.
6116 *
6117 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006118 * @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 +02006119 *
6120 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
6121 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006122static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006123resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02006124{
Michal Vaskobf19d252015-10-08 15:39:17 +02006125 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006126 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02006127 struct lys_restr *must;
6128 struct lyxp_set set;
Michal Vasko53b7da02018-02-13 15:28:42 +01006129 struct ly_ctx *ctx = node->schema->module->ctx;
Michal Vaskobf19d252015-10-08 15:39:17 +02006130
6131 assert(node);
6132 memset(&set, 0, sizeof set);
6133
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006134 if (inout_parent) {
6135 for (schema = lys_parent(node->schema);
6136 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
6137 schema = lys_parent(schema));
6138 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006139 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006140 return -1;
6141 }
6142 must_size = ((struct lys_node_inout *)schema)->must_size;
6143 must = ((struct lys_node_inout *)schema)->must;
6144
6145 /* context node is the RPC/action */
6146 node = node->parent;
6147 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006148 LOGINT(ctx);
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006149 return -1;
6150 }
6151 } else {
6152 switch (node->schema->nodetype) {
6153 case LYS_CONTAINER:
6154 must_size = ((struct lys_node_container *)node->schema)->must_size;
6155 must = ((struct lys_node_container *)node->schema)->must;
6156 break;
6157 case LYS_LEAF:
6158 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
6159 must = ((struct lys_node_leaf *)node->schema)->must;
6160 break;
6161 case LYS_LEAFLIST:
6162 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
6163 must = ((struct lys_node_leaflist *)node->schema)->must;
6164 break;
6165 case LYS_LIST:
6166 must_size = ((struct lys_node_list *)node->schema)->must_size;
6167 must = ((struct lys_node_list *)node->schema)->must;
6168 break;
6169 case LYS_ANYXML:
6170 case LYS_ANYDATA:
6171 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
6172 must = ((struct lys_node_anydata *)node->schema)->must;
6173 break;
6174 case LYS_NOTIF:
6175 must_size = ((struct lys_node_notif *)node->schema)->must_size;
6176 must = ((struct lys_node_notif *)node->schema)->must;
6177 break;
6178 default:
6179 must_size = 0;
6180 break;
6181 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006182 }
6183
6184 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006185 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006186 return -1;
6187 }
6188
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006189 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02006190
Michal Vasko8146d4c2016-05-09 15:50:29 +02006191 if (!set.val.bool) {
Michal Vaskoc04173b2018-03-09 10:43:22 +01006192 if ((ignore_fail == 1) || ((must[i].flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006193 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
6194 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01006195 LOGVAL(ctx, LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006196 if (must[i].emsg) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006197 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006198 }
6199 if (must[i].eapptag) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006200 ly_err_last_set_apptag(ctx, must[i].eapptag);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006201 }
6202 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02006203 }
Michal Vaskobf19d252015-10-08 15:39:17 +02006204 }
6205 }
6206
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006207 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02006208}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006209
Michal Vaskobf19d252015-10-08 15:39:17 +02006210/**
Michal Vasko508a50d2016-09-07 14:50:33 +02006211 * @brief Resolve (find) when condition schema context node. Does not log.
6212 *
6213 * @param[in] schema Schema node with the when condition.
6214 * @param[out] ctx_snode When schema context node.
6215 * @param[out] ctx_snode_type Schema context node type.
6216 */
6217void
6218resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
6219{
6220 const struct lys_node *sparent;
6221
6222 /* find a not schema-only node */
6223 *ctx_snode_type = LYXP_NODE_ELEM;
6224 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
6225 if (schema->nodetype == LYS_AUGMENT) {
6226 sparent = ((struct lys_node_augment *)schema)->target;
6227 } else {
6228 sparent = schema->parent;
6229 }
6230 if (!sparent) {
6231 /* context node is the document root (fake root in our case) */
6232 if (schema->flags & LYS_CONFIG_W) {
6233 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
6234 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02006235 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02006236 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02006237 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskocb45f472018-02-12 10:47:42 +01006238 schema = lys_getnext(NULL, NULL, lys_node_module(schema), LYS_GETNEXT_NOSTATECHECK);
Michal Vasko508a50d2016-09-07 14:50:33 +02006239 break;
6240 }
6241 schema = sparent;
6242 }
6243
6244 *ctx_snode = (struct lys_node *)schema;
6245}
6246
6247/**
Michal Vaskocf024702015-10-08 15:01:42 +02006248 * @brief Resolve (find) when condition context node. Does not log.
6249 *
6250 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02006251 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02006252 * @param[out] ctx_node Context node.
6253 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02006254 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02006255 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02006256 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02006257static int
6258resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
6259 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006260{
Michal Vaskocf024702015-10-08 15:01:42 +02006261 struct lyd_node *parent;
6262 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006263 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02006264 uint16_t i, data_depth, schema_depth;
6265
Michal Vasko508a50d2016-09-07 14:50:33 +02006266 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02006267
Michal Vaskofe989752016-09-08 08:47:26 +02006268 if (node_type == LYXP_NODE_ELEM) {
6269 /* standard element context node */
6270 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
6271 for (sparent = schema, schema_depth = 0;
6272 sparent;
6273 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
6274 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
6275 ++schema_depth;
6276 }
Michal Vaskocf024702015-10-08 15:01:42 +02006277 }
Michal Vaskofe989752016-09-08 08:47:26 +02006278 if (data_depth < schema_depth) {
6279 return -1;
6280 }
Michal Vaskocf024702015-10-08 15:01:42 +02006281
Michal Vasko956e8542016-08-26 09:43:35 +02006282 /* find the corresponding data node */
6283 for (i = 0; i < data_depth - schema_depth; ++i) {
6284 node = node->parent;
6285 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02006286 if (node->schema != schema) {
6287 return -1;
6288 }
Michal Vaskofe989752016-09-08 08:47:26 +02006289 } else {
6290 /* root context node */
6291 while (node->parent) {
6292 node = node->parent;
6293 }
6294 while (node->prev->next) {
6295 node = node->prev;
6296 }
Michal Vaskocf024702015-10-08 15:01:42 +02006297 }
6298
Michal Vaskoa59495d2016-08-22 09:18:58 +02006299 *ctx_node = node;
6300 *ctx_node_type = node_type;
6301 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02006302}
6303
Michal Vasko76c3bd32016-08-24 16:02:52 +02006304/**
6305 * @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 +01006306 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02006307 *
6308 * @param[in] snode Schema node, whose children instances need to be unlinked.
6309 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
6310 * it is moved to point to another sibling still in the original tree.
6311 * @param[in,out] ctx_node When context node, adjusted if needed.
6312 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
6313 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
6314 * Ordering may change, but there will be no semantic change.
6315 *
6316 * @return EXIT_SUCCESS on success, -1 on error.
6317 */
6318static int
6319resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
6320 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
6321{
6322 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006323 const struct lys_node *slast;
Michal Vasko53b7da02018-02-13 15:28:42 +01006324 struct ly_ctx *ctx = snode->module->ctx;
Michal Vasko76c3bd32016-08-24 16:02:52 +02006325
6326 switch (snode->nodetype) {
6327 case LYS_AUGMENT:
6328 case LYS_USES:
6329 case LYS_CHOICE:
6330 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006331 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01006332 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01006333 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
6334 continue;
6335 }
6336
6337 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006338 return -1;
6339 }
6340 }
6341 break;
6342 case LYS_CONTAINER:
6343 case LYS_LIST:
6344 case LYS_LEAF:
6345 case LYS_LEAFLIST:
6346 case LYS_ANYXML:
6347 case LYS_ANYDATA:
6348 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
6349 if (elem->schema == snode) {
6350
6351 if (elem == *ctx_node) {
6352 /* We are going to unlink our context node! This normally cannot happen,
6353 * but we use normal top-level data nodes for faking a document root node,
6354 * so if this is the context node, we just use the next top-level node.
6355 * Additionally, it can even happen that there are no top-level data nodes left,
6356 * all were unlinked, so in this case we pass NULL as the context node/data tree,
6357 * lyxp_eval() can handle this special situation.
6358 */
6359 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006360 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006361 return -1;
6362 }
6363
6364 if (elem->prev == elem) {
6365 /* unlinking last top-level element, use an empty data tree */
6366 *ctx_node = NULL;
6367 } else {
6368 /* in this case just use the previous/last top-level data node */
6369 *ctx_node = elem->prev;
6370 }
6371 } else if (elem == *node) {
6372 /* We are going to unlink the currently processed node. This does not matter that
6373 * much, but we would lose access to the original data tree, so just move our
6374 * pointer somewhere still inside it.
6375 */
6376 if ((*node)->prev != *node) {
6377 *node = (*node)->prev;
6378 } else {
6379 /* the processed node with sibings were all unlinked, oh well */
6380 *node = NULL;
6381 }
6382 }
6383
6384 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01006385 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006386 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006387 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006388 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006389 return -1;
6390 }
6391 } else {
6392 *unlinked_nodes = elem;
6393 }
6394
6395 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
6396 /* there can be only one instance */
6397 break;
6398 }
6399 }
6400 }
6401 break;
6402 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01006403 LOGINT(ctx);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006404 return -1;
6405 }
6406
6407 return EXIT_SUCCESS;
6408}
6409
6410/**
6411 * @brief Relink the unlinked nodes back.
6412 *
6413 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
6414 * we simply need a sibling from the original data tree.
6415 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
6416 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
6417 * or the sibling of \p unlinked_nodes.
6418 *
6419 * @return EXIT_SUCCESS on success, -1 on error.
6420 */
6421static int
6422resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
6423{
6424 struct lyd_node *elem;
6425
6426 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006427 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006428 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006429 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006430 return -1;
6431 }
6432 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01006433 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006434 return -1;
6435 }
6436 }
6437 }
6438
6439 return EXIT_SUCCESS;
6440}
6441
Radek Krejci03b71f72016-03-16 11:10:09 +01006442int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006443resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01006444{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006445 int ret = 0;
6446 uint8_t must_size;
6447 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02006448
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006449 assert(node);
6450
6451 schema = node->schema;
6452
6453 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02006454 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01006455 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006456 must_size = ((struct lys_node_container *)schema)->must_size;
6457 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006458 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006459 must_size = ((struct lys_node_leaf *)schema)->must_size;
6460 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006461 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006462 must_size = ((struct lys_node_leaflist *)schema)->must_size;
6463 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006464 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006465 must_size = ((struct lys_node_list *)schema)->must_size;
6466 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006467 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02006468 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006469 must_size = ((struct lys_node_anydata *)schema)->must_size;
6470 break;
6471 case LYS_NOTIF:
6472 must_size = ((struct lys_node_notif *)schema)->must_size;
6473 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006474 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006475 must_size = 0;
6476 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01006477 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006478
6479 if (must_size) {
6480 ++ret;
6481 }
6482
6483 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
6484 if (!node->prev->next) {
6485 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
6486 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
6487 ret += 0x2;
6488 }
6489 }
6490
6491 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01006492}
6493
Michal Vaskodd962292018-09-10 08:53:01 +02006494static struct lys_when *
6495snode_get_when(const struct lys_node *schema)
6496{
6497 switch (schema->nodetype) {
6498 case LYS_CONTAINER:
6499 return ((struct lys_node_container *)schema)->when;
6500 case LYS_CHOICE:
6501 return ((struct lys_node_choice *)schema)->when;
6502 case LYS_LEAF:
6503 return ((struct lys_node_leaf *)schema)->when;
6504 case LYS_LEAFLIST:
6505 return ((struct lys_node_leaflist *)schema)->when;
6506 case LYS_LIST:
6507 return ((struct lys_node_list *)schema)->when;
6508 case LYS_ANYDATA:
6509 case LYS_ANYXML:
6510 return ((struct lys_node_anydata *)schema)->when;
6511 case LYS_CASE:
6512 return ((struct lys_node_case *)schema)->when;
6513 case LYS_USES:
6514 return ((struct lys_node_uses *)schema)->when;
6515 case LYS_AUGMENT:
6516 return ((struct lys_node_augment *)schema)->when;
6517 default:
6518 return NULL;
6519 }
6520}
6521
Radek Krejci01696bf2016-03-18 13:19:36 +01006522int
Radek Krejci46165822016-08-26 14:06:27 +02006523resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01006524{
Radek Krejci46165822016-08-26 14:06:27 +02006525 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01006526
Radek Krejci46165822016-08-26 14:06:27 +02006527 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01006528
Michal Vaskodd962292018-09-10 08:53:01 +02006529 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && snode_get_when(schema)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006530 return 1;
6531 }
6532
Radek Krejci46165822016-08-26 14:06:27 +02006533 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01006534 goto check_augment;
6535
Radek Krejci46165822016-08-26 14:06:27 +02006536 while (parent) {
6537 /* stop conditions */
6538 if (!mode) {
6539 /* stop on node that can be instantiated in data tree */
6540 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6541 break;
6542 }
6543 } else {
6544 /* stop on the specified node */
6545 if (parent == stop) {
6546 break;
6547 }
6548 }
6549
Michal Vaskodd962292018-09-10 08:53:01 +02006550 if (snode_get_when(parent)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006551 return 1;
6552 }
6553check_augment:
6554
Michal Vaskodd962292018-09-10 08:53:01 +02006555 if (parent->parent && (parent->parent->nodetype == LYS_AUGMENT) && snode_get_when(parent->parent)) {
Michal Vaskoe3655562016-08-24 15:56:17 +02006556 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01006557 }
6558 parent = lys_parent(parent);
6559 }
6560
6561 return 0;
6562}
6563
Michal Vaskocf024702015-10-08 15:01:42 +02006564/**
6565 * @brief Resolve (check) all when conditions relevant for \p node.
6566 * Logs directly.
6567 *
6568 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskoe446b092017-08-11 10:58:09 +02006569 * @param[in] ignore_fail 1 if when does not have to be satisfied, 2 if it does not have to be satisfied
6570 * only when requiring external dependencies.
Michal Vaskocf024702015-10-08 15:01:42 +02006571 *
Radek Krejci03b71f72016-03-16 11:10:09 +01006572 * @return
6573 * -1 - error, ly_errno is set
Michal Vasko0b963112017-08-11 12:45:36 +02006574 * 0 - all "when" statements true
6575 * 0, ly_vecode = LYVE_NOWHEN - some "when" statement false, returned in failed_when
Radek Krejci03b71f72016-03-16 11:10:09 +01006576 * 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 +02006577 */
Radek Krejci46165822016-08-26 14:06:27 +02006578int
Michal Vasko0b963112017-08-11 12:45:36 +02006579resolve_when(struct lyd_node *node, int ignore_fail, struct lys_when **failed_when)
Michal Vaskocf024702015-10-08 15:01:42 +02006580{
Michal Vasko76c3bd32016-08-24 16:02:52 +02006581 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02006582 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02006583 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02006584 enum lyxp_node_type ctx_node_type;
Michal Vasko53b7da02018-02-13 15:28:42 +01006585 struct ly_ctx *ctx = node->schema->module->ctx;
Radek Krejci51093642016-03-29 10:14:59 +02006586 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02006587
6588 assert(node);
6589 memset(&set, 0, sizeof set);
6590
Michal Vaskodd962292018-09-10 08:53:01 +02006591 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && snode_get_when(node->schema)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02006592 /* make the node dummy for the evaluation */
6593 node->validity |= LYD_VAL_INUSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006594 rc = lyxp_eval(snode_get_when(node->schema)->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006595 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006596 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006597 if (rc) {
6598 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006599 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006600 }
Radek Krejci51093642016-03-29 10:14:59 +02006601 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006602 }
6603
Radek Krejci03b71f72016-03-16 11:10:09 +01006604 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006605 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006606 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006607 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006608 if ((ignore_fail == 1) || ((snode_get_when(node->schema)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
Michal Vaskoc04173b2018-03-09 10:43:22 +01006609 && (ignore_fail == 2))) {
Michal Vaskodd962292018-09-10 08:53:01 +02006610 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(node->schema)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006611 } else {
Michal Vaskodd962292018-09-10 08:53:01 +02006612 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(node->schema)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006613 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006614 *failed_when = snode_get_when(node->schema);
Michal Vasko0b963112017-08-11 12:45:36 +02006615 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006616 goto cleanup;
6617 }
Michal Vaskocf024702015-10-08 15:01:42 +02006618 }
Radek Krejci51093642016-03-29 10:14:59 +02006619
6620 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006621 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006622 }
6623
Michal Vasko90fc2a32016-08-24 15:58:58 +02006624 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006625 goto check_augment;
6626
6627 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006628 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
Michal Vaskodd962292018-09-10 08:53:01 +02006629 if (snode_get_when(sparent)) {
Michal Vaskocf024702015-10-08 15:01:42 +02006630 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006631 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006632 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006633 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006634 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006635 }
6636 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006637
6638 unlinked_nodes = NULL;
6639 /* we do not want our node pointer to change */
6640 tmp_node = node;
6641 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6642 if (rc) {
6643 goto cleanup;
6644 }
6645
Michal Vaskodd962292018-09-10 08:53:01 +02006646 rc = lyxp_eval(snode_get_when(sparent)->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006647 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006648
6649 if (unlinked_nodes && ctx_node) {
6650 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6651 rc = -1;
6652 goto cleanup;
6653 }
6654 }
6655
Radek Krejci03b71f72016-03-16 11:10:09 +01006656 if (rc) {
6657 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006658 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006659 }
Radek Krejci51093642016-03-29 10:14:59 +02006660 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006661 }
6662
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006663 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006664 if (!set.val.bool) {
Michal Vaskodd962292018-09-10 08:53:01 +02006665 if ((ignore_fail == 1) || ((snode_get_when(sparent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
6666 && (ignore_fail == 2))) {
6667 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.", snode_get_when(sparent)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006668 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006669 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006670 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006671 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006672 *failed_when = snode_get_when(sparent);
Michal Vasko0b963112017-08-11 12:45:36 +02006673 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006674 goto cleanup;
6675 }
Michal Vaskocf024702015-10-08 15:01:42 +02006676 }
Radek Krejci51093642016-03-29 10:14:59 +02006677
6678 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006679 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006680 }
6681
6682check_augment:
Michal Vaskodd962292018-09-10 08:53:01 +02006683 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && snode_get_when(sparent->parent))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006684 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006685 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006686 if (rc) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006687 LOGINT(ctx);
Radek Krejci51093642016-03-29 10:14:59 +02006688 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006689 }
6690 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006691
6692 unlinked_nodes = NULL;
6693 tmp_node = node;
6694 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6695 if (rc) {
6696 goto cleanup;
6697 }
6698
Michal Vaskodd962292018-09-10 08:53:01 +02006699 rc = lyxp_eval(snode_get_when(sparent->parent)->cond, ctx_node, ctx_node_type,
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006700 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006701
6702 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6703 * so the tree did not actually change and there is nothing for us to do
6704 */
6705 if (unlinked_nodes && ctx_node) {
6706 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6707 rc = -1;
6708 goto cleanup;
6709 }
6710 }
6711
Radek Krejci03b71f72016-03-16 11:10:09 +01006712 if (rc) {
6713 if (rc == 1) {
Michal Vaskodd962292018-09-10 08:53:01 +02006714 LOGVAL(ctx, LYE_INWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006715 }
Radek Krejci51093642016-03-29 10:14:59 +02006716 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006717 }
6718
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006719 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006720 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006721 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskodd962292018-09-10 08:53:01 +02006722 if ((ignore_fail == 1) || ((snode_get_when(sparent->parent)->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP))
Michal Vaskoc04173b2018-03-09 10:43:22 +01006723 && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006724 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vaskodd962292018-09-10 08:53:01 +02006725 snode_get_when(sparent->parent)->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006726 } else {
Michal Vaskodd962292018-09-10 08:53:01 +02006727 LOGVAL(ctx, LYE_NOWHEN, LY_VLOG_LYD, node, snode_get_when(sparent->parent)->cond);
Michal Vasko0b963112017-08-11 12:45:36 +02006728 if (failed_when) {
Michal Vaskodd962292018-09-10 08:53:01 +02006729 *failed_when = snode_get_when(sparent->parent);
Michal Vasko0b963112017-08-11 12:45:36 +02006730 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006731 goto cleanup;
6732 }
Michal Vaskocf024702015-10-08 15:01:42 +02006733 }
Radek Krejci51093642016-03-29 10:14:59 +02006734
6735 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006736 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006737 }
6738
Michal Vasko90fc2a32016-08-24 15:58:58 +02006739 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006740 }
6741
Radek Krejci0b7704f2016-03-18 12:16:14 +01006742 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006743
Radek Krejci51093642016-03-29 10:14:59 +02006744cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006745 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006746 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006747 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006748}
6749
Radek Krejcicbb473e2016-09-16 14:48:32 +02006750static int
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006751check_type_union_leafref(struct lys_type *type)
6752{
6753 uint8_t i;
6754
6755 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6756 /* go through unions and look for leafref */
6757 for (i = 0; i < type->info.uni.count; ++i) {
6758 switch (type->info.uni.types[i].base) {
6759 case LY_TYPE_LEAFREF:
6760 return 1;
6761 case LY_TYPE_UNION:
6762 if (check_type_union_leafref(&type->info.uni.types[i])) {
6763 return 1;
6764 }
6765 break;
6766 default:
6767 break;
6768 }
6769 }
6770
6771 return 0;
6772 }
6773
6774 /* just inherit the flag value */
6775 return type->der->has_union_leafref;
6776}
6777
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006778/**
Michal Vaskobb211122015-08-19 14:03:11 +02006779 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006780 *
6781 * @param[in] mod Main module.
6782 * @param[in] item Item to resolve. Type determined by \p type.
6783 * @param[in] type Type of the unresolved item.
6784 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006785 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006786 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006787 *
6788 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6789 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006790static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006791resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vaskof96dfb62017-08-17 12:23:49 +02006792 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006793{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006794 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Michal Vasko53b7da02018-02-13 15:28:42 +01006795 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006796 unsigned int j;
Michal Vasko53b7da02018-02-13 15:28:42 +01006797 struct ly_ctx * ctx = mod->ctx;
Radek Krejci80056d52017-01-05 13:13:33 +01006798 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006799 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006800 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006801
Radek Krejcic79c6b12016-07-26 15:11:49 +02006802 struct ly_set *refs, *procs;
6803 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006804 struct lys_ident *ident;
6805 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006806 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006807 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006808 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006809 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006810 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006811 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006812 struct lys_ext_instance *ext, **extlist;
6813 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006814
6815 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006816 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006817 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006818 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006819 ident = item;
6820
Radek Krejci018f1f52016-08-03 16:01:20 +02006821 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006822 break;
6823 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006824 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006825 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006826 stype = item;
6827
Radek Krejci018f1f52016-08-03 16:01:20 +02006828 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006829 break;
6830 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006831 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006832 stype = item;
6833
Michal Vasko74083ec2018-06-15 10:00:12 +02006834 rc = resolve_schema_leafref(stype, node, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006835 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006836 case UNRES_TYPE_DER_EXT:
6837 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006838 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006839 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006840 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006841 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006842 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006843 /* parent */
6844 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006845 stype = item;
6846
Michal Vasko88c29542015-11-27 14:57:53 +01006847 /* HACK type->der is temporarily unparsed type statement */
6848 yin = (struct lyxml_elem *)stype->der;
6849 stype->der = NULL;
6850
Pavol Vicana0e4e672016-02-24 12:20:04 +01006851 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6852 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006853 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006854
6855 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006856 /* may try again later */
6857 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006858 } else {
6859 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006860 lydict_remove(ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006861 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006862 }
6863
Michal Vasko88c29542015-11-27 14:57:53 +01006864 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006865 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006866 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006867 /* we need to always be able to free this, it's safe only in this case */
Michal Vasko53b7da02018-02-13 15:28:42 +01006868 lyxml_free(ctx, yin);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006869 } else {
6870 /* may try again later, put all back how it was */
6871 stype->der = (struct lys_tpdf *)yin;
6872 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006873 }
Radek Krejcic13db382016-08-16 10:52:42 +02006874 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006875 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006876 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006877 LOGWRN(ctx, "The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
Radek Krejci2c2fce82016-08-01 13:52:26 +02006878 }
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006879
6880 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6881 /* fill typedef union leafref flag */
6882 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6883 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6884 /* copy the type in case it has union leafref flag */
6885 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006886 LOGERR(ctx, LY_EINT, "Failed to duplicate type.");
Michal Vaskoe1c7a822017-06-30 13:15:18 +02006887 return -1;
6888 }
6889 }
Michal Vasko101658e2018-06-05 15:05:54 +02006890 } else if (rc == EXIT_FAILURE && !(stype->value_flags & LY_VALUE_UNRESGRP)) {
Radek Krejcic13db382016-08-16 10:52:42 +02006891 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6892 * 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 +02006893 * grouping. The grouping cannot be used unless the unres counter is 0.
Michal Vasko70bf8e52018-03-26 11:32:33 +02006894 * To remember that the grouping already increased the counter, the LYTYPE_GRP is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006895 * of the type's base member. */
6896 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6897 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006898 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006899 LOGERR(ctx, LY_EINT, "Too many unresolved items (type) inside a grouping.");
Radek Krejci93def382017-05-24 15:33:48 +02006900 return -1;
6901 }
Michal Vasko101658e2018-06-05 15:05:54 +02006902 stype->value_flags |= LY_VALUE_UNRESGRP;
Radek Krejcic13db382016-08-16 10:52:42 +02006903 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006904 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006905 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006906 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006907 iff_data = str_snode;
6908 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006909 if (!rc) {
6910 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006911 if (iff_data->infeature) {
6912 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6913 feat = *((struct lys_feature **)item);
6914 if (!feat->depfeatures) {
6915 feat->depfeatures = ly_set_new();
6916 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006917 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006918 }
6919 /* cleanup temporary data */
Michal Vasko53b7da02018-02-13 15:28:42 +01006920 lydict_remove(ctx, iff_data->fname);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006921 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006922 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006923 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006924 case UNRES_FEATURE:
6925 feat = (struct lys_feature *)item;
6926
6927 if (feat->iffeature_size) {
6928 refs = ly_set_new();
6929 procs = ly_set_new();
6930 ly_set_add(procs, feat, 0);
6931
6932 while (procs->number) {
6933 ref = procs->set.g[procs->number - 1];
6934 ly_set_rm_index(procs, procs->number - 1);
6935
6936 for (i = 0; i < ref->iffeature_size; i++) {
6937 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6938 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006939 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006940 if (ref->iffeature[i].features[j - 1] == feat) {
Michal Vasko53b7da02018-02-13 15:28:42 +01006941 LOGVAL(ctx, LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006942 goto featurecheckdone;
6943 }
6944
6945 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6946 k = refs->number;
6947 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6948 /* not yet seen feature, add it for processing */
6949 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6950 }
6951 }
6952 } else {
6953 /* forward reference */
6954 rc = EXIT_FAILURE;
6955 goto featurecheckdone;
6956 }
6957 }
6958
6959 }
6960 }
6961 rc = EXIT_SUCCESS;
6962
6963featurecheckdone:
6964 ly_set_free(refs);
6965 ly_set_free(procs);
6966 }
6967
6968 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006969 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006970 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006971 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006972 case UNRES_TYPEDEF_DFLT:
6973 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006974 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006975 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006976 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006977 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vasko7d894922018-11-12 11:55:55 +01006978 if ((rc == EXIT_FAILURE) && !parent_type) {
6979 for (par_grp = (struct lys_node *)stype->parent;
6980 par_grp && (par_grp->nodetype != LYS_GROUPING);
6981 par_grp = lys_parent(par_grp));
6982 if (par_grp) {
6983 /* checking default value in a grouping finished with forward reference means we cannot check the value */
6984 rc = EXIT_SUCCESS;
6985 }
6986 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006987 break;
6988 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006989 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006990 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006991 choic = item;
6992
Radek Krejcie00d2312016-08-12 15:27:49 +02006993 if (!choic->dflt) {
6994 choic->dflt = resolve_choice_dflt(choic, expr);
6995 }
Michal Vasko7955b362015-09-04 14:18:15 +02006996 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006997 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006998 } else {
6999 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02007000 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007001 break;
7002 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01007003 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007004 break;
7005 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02007006 unique_info = (struct unres_list_uniq *)item;
7007 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007008 break;
Michal Vasko7178e692016-02-12 15:58:05 +01007009 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01007010 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01007011 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02007012 case UNRES_XPATH:
7013 node = (struct lys_node *)item;
Michal Vasko895c11f2018-03-12 11:35:58 +01007014 rc = check_xpath(node, 1);
Michal Vasko508a50d2016-09-07 14:50:33 +02007015 break;
Michal Vasko0f437062018-06-08 15:52:39 +02007016 case UNRES_MOD_IMPLEMENT:
7017 rc = lys_make_implemented_r(mod, unres);
7018 break;
Radek Krejcie534c132016-11-23 13:32:31 +01007019 case UNRES_EXT:
7020 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01007021 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01007022 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01007023 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01007024 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01007025 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01007026 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01007027 if (eplugin) {
7028 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01007029 u = malloc(sizeof *u);
Michal Vasko53b7da02018-02-13 15:28:42 +01007030 LY_CHECK_ERR_RETURN(!u, LOGMEM(ctx), -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01007031 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01007032 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
7033 /* something really bad happend since the extension finalization is not actually
7034 * being resolved while adding into unres, so something more serious with the unres
7035 * list itself must happened */
7036 return -1;
7037 }
Radek Krejci80056d52017-01-05 13:13:33 +01007038 }
7039 }
Radek Krejci79685c92017-02-17 10:49:43 +01007040 }
7041 if (!rc || rc == -1) {
7042 /* cleanup on success or fatal error */
7043 if (ext_data->datatype == LYS_IN_YIN) {
7044 /* YIN */
Michal Vasko53b7da02018-02-13 15:28:42 +01007045 lyxml_free(ctx, ext_data->data.yin);
Radek Krejci79685c92017-02-17 10:49:43 +01007046 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01007047 /* YANG */
7048 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01007049 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01007050 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01007051 }
7052 break;
Radek Krejci80056d52017-01-05 13:13:33 +01007053 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01007054 u = (uint8_t *)str_snode;
7055 ext = (*(struct lys_ext_instance ***)item)[*u];
7056 free(u);
7057
Radek Krejci80056d52017-01-05 13:13:33 +01007058 eplugin = ext->def->plugin;
7059
7060 /* inherit */
7061 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
7062 root = (struct lys_node *)ext->parent;
7063 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
7064 LY_TREE_DFS_BEGIN(root->child, next, node) {
7065 /* first, check if the node already contain instance of the same extension,
7066 * in such a case we won't inherit. In case the node was actually defined as
7067 * augment data, we are supposed to check the same way also the augment node itself */
7068 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
7069 goto inherit_dfs_sibling;
7070 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
7071 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
7072 goto inherit_dfs_sibling;
7073 }
7074
7075 if (eplugin->check_inherit) {
7076 /* we have a callback to check the inheritance, use it */
7077 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
7078 case 0:
7079 /* yes - continue with the inheriting code */
7080 break;
7081 case 1:
7082 /* no - continue with the node's sibling */
7083 goto inherit_dfs_sibling;
7084 case 2:
7085 /* no, but continue with the children, just skip the inheriting code for this node */
7086 goto inherit_dfs_child;
7087 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007088 LOGERR(ctx, LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
Radek Krejci80056d52017-01-05 13:13:33 +01007089 ext->def->module->name, ext->def->name, rc);
7090 }
7091 }
7092
7093 /* inherit the extension */
7094 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Michal Vasko53b7da02018-02-13 15:28:42 +01007095 LY_CHECK_ERR_RETURN(!extlist, LOGMEM(ctx), -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007096 extlist[node->ext_size] = malloc(sizeof **extlist);
Michal Vasko53b7da02018-02-13 15:28:42 +01007097 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM(ctx); node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01007098 memcpy(extlist[node->ext_size], ext, sizeof *ext);
7099 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
7100
7101 node->ext = extlist;
7102 node->ext_size++;
7103
7104inherit_dfs_child:
7105 /* modification of - select element for the next run - children first */
7106 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
7107 next = NULL;
7108 } else {
7109 next = node->child;
7110 }
7111 if (!next) {
7112inherit_dfs_sibling:
7113 /* no children, try siblings */
7114 next = node->next;
7115 }
7116 while (!next) {
7117 /* go to the parent */
7118 node = lys_parent(node);
7119
7120 /* we are done if we are back in the root (the starter's parent */
7121 if (node == root) {
7122 break;
7123 }
7124
7125 /* parent is already processed, go to its sibling */
7126 next = node->next;
7127 }
7128 }
7129 }
7130 }
7131
7132 /* final check */
7133 if (eplugin->check_result) {
7134 if ((*eplugin->check_result)(ext)) {
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007135 LOGERR(ctx, LY_EPLUGIN, "Resolving extension failed.");
Radek Krejci80056d52017-01-05 13:13:33 +01007136 return -1;
7137 }
7138 }
7139
7140 rc = 0;
7141 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007142 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007143 LOGINT(ctx);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007144 break;
7145 }
7146
Radek Krejci54081ce2016-08-12 15:21:47 +02007147 if (has_str && !rc) {
7148 /* the string is no more needed in case of success.
7149 * In case of forward reference, we will try to resolve the string later */
Michal Vasko53b7da02018-02-13 15:28:42 +01007150 lydict_remove(ctx, str_snode);
Radek Krejci4f78b532016-02-17 13:43:00 +01007151 }
7152
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007153 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007154}
7155
Michal Vaskof02e3742015-08-05 16:27:02 +02007156/* logs directly */
7157static void
Radek Krejci48464ed2016-03-17 15:44:09 +01007158print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007159{
Michal Vaskocb34dc62016-05-20 14:38:37 +02007160 struct lyxml_elem *xml;
7161 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007162 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01007163 const char *name = NULL;
7164 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007165
Michal Vaskof02e3742015-08-05 16:27:02 +02007166 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02007167 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007168 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007169 break;
7170 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007171 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007172 break;
7173 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01007174 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
7175 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02007176 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01007177 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02007178 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02007179 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02007180 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
7181 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01007182 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007183 } else {
7184 LY_TREE_FOR(xml->attr, attr) {
7185 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01007186 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02007187 break;
7188 }
7189 }
7190 assert(attr);
7191 }
Radek Krejcie534c132016-11-23 13:32:31 +01007192 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007193 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007194 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007195 iff_data = str_node;
7196 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02007197 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02007198 case UNRES_FEATURE:
7199 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
7200 ((struct lys_feature *)item)->name);
7201 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02007202 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01007203 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02007204 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01007205 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02007206 case UNRES_TYPE_DFLT:
Michal Vaskoba835cd2018-02-23 09:25:48 +01007207 if (*(char **)str_node) {
7208 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", *(char **)str_node);
Radek Krejci2e2de832016-10-13 16:12:26 +02007209 } /* else no default value in the type itself, but we are checking some restrictions against
7210 * possible default value of some base type. The failure is caused by not resolved base type,
7211 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02007212 break;
7213 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007214 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007215 break;
7216 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01007217 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007218 break;
7219 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01007220 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02007221 break;
Michal Vasko7178e692016-02-12 15:58:05 +01007222 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01007223 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
7224 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01007225 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02007226 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01007227 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
7228 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02007229 break;
Radek Krejcie534c132016-11-23 13:32:31 +01007230 case UNRES_EXT:
7231 extinfo = (struct unres_ext *)str_node;
7232 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
7233 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
7234 break;
Michal Vaskocf024702015-10-08 15:01:42 +02007235 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01007236 LOGINT(NULL);
Michal Vaskof02e3742015-08-05 16:27:02 +02007237 break;
7238 }
7239}
7240
Michal Vasko0f437062018-06-08 15:52:39 +02007241static int
7242resolve_unres_schema_types(struct unres_schema *unres, enum UNRES_ITEM types, struct ly_ctx *ctx, int forward_ref,
7243 int print_all_errors, uint32_t *resolved)
7244{
7245 uint32_t i, unres_count, res_count;
7246 int ret = 0, rc;
7247 struct ly_err_item *prev_eitem;
7248 enum int_log_opts prev_ilo;
7249 LY_ERR prev_ly_errno;
7250
7251 /* if there can be no forward references, every failure is final, so we can print it directly */
7252 if (forward_ref) {
7253 prev_ly_errno = ly_errno;
7254 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
7255 }
7256
7257 do {
7258 unres_count = 0;
7259 res_count = 0;
7260
7261 for (i = 0; i < unres->count; ++i) {
7262 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7263 * if-features are resolved here to make sure that we will have all if-features for
7264 * later check of feature circular dependency */
7265 if (unres->type[i] & types) {
7266 ++unres_count;
7267 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7268 if (unres->type[i] == UNRES_EXT_FINALIZE) {
7269 /* to avoid double free */
7270 unres->type[i] = UNRES_RESOLVED;
7271 }
7272 if (!rc || (unres->type[i] == UNRES_XPATH)) {
7273 /* invalid XPath can never cause an error, only a warning */
7274 if (unres->type[i] == UNRES_LIST_UNIQ) {
7275 /* free the allocated structure */
7276 free(unres->item[i]);
7277 }
7278
7279 unres->type[i] = UNRES_RESOLVED;
7280 ++(*resolved);
7281 ++res_count;
7282 } else if ((rc == EXIT_FAILURE) && forward_ref) {
7283 /* forward reference, erase errors */
7284 ly_err_free_next(ctx, prev_eitem);
7285 } else if (print_all_errors) {
7286 /* just so that we quit the loop */
7287 ++res_count;
7288 ret = -1;
7289 } else {
Michal Vaskoffdf4ce2018-08-17 10:31:49 +02007290 if (forward_ref) {
7291 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
7292 }
Michal Vasko0f437062018-06-08 15:52:39 +02007293 return -1;
7294 }
7295 }
7296 }
7297 } while (res_count && (res_count < unres_count));
7298
7299 if (res_count < unres_count) {
7300 assert(forward_ref);
7301 /* just print the errors (but we must free the ones we have and get them again :-/ ) */
7302 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7303
7304 for (i = 0; i < unres->count; ++i) {
7305 if (unres->type[i] & types) {
7306 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres);
7307 }
7308 }
7309 return -1;
7310 }
7311
7312 if (forward_ref) {
7313 /* restore log */
7314 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7315 ly_errno = prev_ly_errno;
7316 }
7317
7318 return ret;
7319}
7320
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007321/**
Michal Vaskobb211122015-08-19 14:03:11 +02007322 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007323 *
7324 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007325 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007326 *
Michal Vasko92b8a382015-08-19 14:03:49 +02007327 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007328 */
Michal Vaskof02e3742015-08-05 16:27:02 +02007329int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007330resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02007331{
Michal Vasko0f437062018-06-08 15:52:39 +02007332 uint32_t resolved = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007333
7334 assert(unres);
7335
Michal Vaskoe8734262016-09-29 14:12:06 +02007336 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko51054ca2015-08-12 12:20:00 +02007337
Michal Vasko0f437062018-06-08 15:52:39 +02007338 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
7339 * if-features are resolved here to make sure that we will have all if-features for
7340 * later check of feature circular dependency */
7341 if (resolve_unres_schema_types(unres, UNRES_USES | UNRES_IFFEAT | UNRES_TYPE_DER | UNRES_TYPE_DER_TPDF | UNRES_TYPE_DER_TPDF
7342 | UNRES_TYPE_LEAFREF | UNRES_MOD_IMPLEMENT | UNRES_AUGMENT | UNRES_CHOICE_DFLT | UNRES_IDENT,
7343 mod->ctx, 1, 0, &resolved)) {
Michal Vasko92b8a382015-08-19 14:03:49 +02007344 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007345 }
7346
Michal Vasko0f437062018-06-08 15:52:39 +02007347 /* another batch of resolved items */
7348 if (resolve_unres_schema_types(unres, UNRES_TYPE_IDENTREF | UNRES_FEATURE | UNRES_TYPEDEF_DFLT | UNRES_TYPE_DFLT
7349 | UNRES_LIST_KEYS | UNRES_LIST_UNIQ | UNRES_EXT, mod->ctx, 1, 0, &resolved)) {
7350 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007351 }
7352
Michal Vasko0f437062018-06-08 15:52:39 +02007353 /* print xpath warnings and finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
7354 if (resolve_unres_schema_types(unres, UNRES_XPATH | UNRES_EXT_FINALIZE, mod->ctx, 0, 1, &resolved)) {
7355 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007356 }
7357
Michal Vaskoe8734262016-09-29 14:12:06 +02007358 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01007359 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007360 return EXIT_SUCCESS;
7361}
7362
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007363/**
Michal Vaskobb211122015-08-19 14:03:11 +02007364 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007365 *
7366 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007367 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007368 * @param[in] item Item to resolve. Type determined by \p type.
7369 * @param[in] type Type of the unresolved item.
7370 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007371 *
Michal Vasko3767fb22016-07-21 12:10:57 +02007372 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007373 */
7374int
Radek Krejci48464ed2016-03-17 15:44:09 +01007375unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
7376 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007377{
Radek Krejci54081ce2016-08-12 15:21:47 +02007378 int rc;
7379 const char *dictstr;
7380
7381 dictstr = lydict_insert(mod->ctx, str, 0);
7382 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
7383
Radek Krejcid9c0ce22017-01-20 15:20:16 +01007384 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02007385 lydict_remove(mod->ctx, dictstr);
7386 }
7387 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007388}
7389
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007390/**
Michal Vaskobb211122015-08-19 14:03:11 +02007391 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007392 *
7393 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007394 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007395 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01007396 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007397 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007398 *
Radek Krejci62f7aad2017-10-26 14:53:52 +02007399 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007400 */
7401int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007402unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01007403 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007404{
Michal Vasko53b7da02018-02-13 15:28:42 +01007405 int rc;
Radek Krejci62f7aad2017-10-26 14:53:52 +02007406 uint32_t u;
Michal Vasko53b7da02018-02-13 15:28:42 +01007407 enum int_log_opts prev_ilo;
7408 struct ly_err_item *prev_eitem;
7409 LY_ERR prev_ly_errno;
Michal Vasko88c29542015-11-27 14:57:53 +01007410 struct lyxml_elem *yin;
Michal Vasko53b7da02018-02-13 15:28:42 +01007411 struct ly_ctx *ctx = mod->ctx;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007412
Michal Vasko0f437062018-06-08 15:52:39 +02007413 assert(unres && (item || (type == UNRES_MOD_IMPLEMENT)) && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID)
7414 && (type != UNRES_WHEN) && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007415
Radek Krejci850a5de2016-11-08 14:06:40 +01007416 /* check for duplicities in unres */
7417 for (u = 0; u < unres->count; u++) {
7418 if (unres->type[u] == type && unres->item[u] == item &&
7419 unres->str_snode[u] == snode && unres->module[u] == mod) {
Radek Krejci62f7aad2017-10-26 14:53:52 +02007420 /* duplication can happen when the node contains multiple statements of the same type to check,
7421 * this can happen for example when refinement is being applied, so we just postpone the processing
7422 * and do not duplicate the information */
7423 return EXIT_FAILURE;
Radek Krejci850a5de2016-11-08 14:06:40 +01007424 }
7425 }
7426
Michal Vasko0f437062018-06-08 15:52:39 +02007427 if ((type == UNRES_EXT_FINALIZE) || (type == UNRES_XPATH) || (type == UNRES_MOD_IMPLEMENT)) {
Michal Vaskof96dfb62017-08-17 12:23:49 +02007428 /* extension finalization is not even tried when adding the item into the inres list,
Michal Vasko0f437062018-06-08 15:52:39 +02007429 * xpath is not tried because it would hide some potential warnings,
7430 * implementing module must be deferred because some other nodes can be added that will need to be traversed
7431 * and their targets made implemented */
Radek Krejcic293bac2017-02-27 11:25:28 +01007432 rc = EXIT_FAILURE;
7433 } else {
Michal Vasko53b7da02018-02-13 15:28:42 +01007434 prev_ly_errno = ly_errno;
7435 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007436
Michal Vasko53b7da02018-02-13 15:28:42 +01007437 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Radek Krejci80056d52017-01-05 13:13:33 +01007438 if (rc != EXIT_FAILURE) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007439 ly_ilo_restore(ctx, prev_ilo, prev_eitem, rc == -1 ? 1 : 0);
7440 if (rc != -1) {
7441 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007442 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007443
Radek Krejci80056d52017-01-05 13:13:33 +01007444 if (type == UNRES_LIST_UNIQ) {
7445 /* free the allocated structure */
7446 free(item);
7447 } else if (rc == -1 && type == UNRES_IFFEAT) {
7448 /* free the allocated resources */
7449 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02007450 }
Radek Krejci80056d52017-01-05 13:13:33 +01007451 return rc;
7452 } else {
7453 /* erase info about validation errors */
Michal Vasko53b7da02018-02-13 15:28:42 +01007454 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
7455 ly_errno = prev_ly_errno;
Radek Krejci80056d52017-01-05 13:13:33 +01007456 }
Michal Vaskof02e3742015-08-05 16:27:02 +02007457
Radek Krejci80056d52017-01-05 13:13:33 +01007458 print_unres_schema_item_fail(item, type, snode);
7459
7460 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
7461 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
7462 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
7463 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
7464 lyxml_unlink_elem(mod->ctx, yin, 1);
7465 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
7466 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01007467 }
Michal Vasko88c29542015-11-27 14:57:53 +01007468 }
7469
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007470 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007471 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Michal Vasko53b7da02018-02-13 15:28:42 +01007472 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007473 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007474 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01007475 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(ctx), -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007476 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007477 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Michal Vasko53b7da02018-02-13 15:28:42 +01007478 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM(ctx), -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007479 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007480 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Michal Vasko53b7da02018-02-13 15:28:42 +01007481 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM(ctx), -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007482 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007483
Michal Vasko3767fb22016-07-21 12:10:57 +02007484 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007485}
7486
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007487/**
Michal Vaskobb211122015-08-19 14:03:11 +02007488 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007489 *
7490 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007491 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007492 * @param[in] item Old item to be resolved.
7493 * @param[in] type Type of the old unresolved item.
7494 * @param[in] new_item New item to use in the duplicate.
7495 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007496 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007497 */
Michal Vaskodad19402015-08-06 09:51:53 +02007498int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007499unres_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 +02007500{
7501 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007502 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007503 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007504
Michal Vaskocf024702015-10-08 15:01:42 +02007505 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007506
Radek Krejcid09d1a52016-08-11 14:05:45 +02007507 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7508 if (type == UNRES_LIST_UNIQ) {
7509 aux_uniq.list = item;
7510 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7511 item = &aux_uniq;
7512 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007513 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007514
7515 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007516 if (type == UNRES_LIST_UNIQ) {
7517 free(new_item);
7518 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007519 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007520 }
7521
Radek Krejcic79c6b12016-07-26 15:11:49 +02007522 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007523 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007524 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007525 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007526 return -1;
7527 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007528 } else if (type == UNRES_IFFEAT) {
7529 /* duplicate unres_iffeature_data */
7530 iff_data = malloc(sizeof *iff_data);
Michal Vasko53b7da02018-02-13 15:28:42 +01007531 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM(mod->ctx), -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007532 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7533 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7534 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007535 LOGINT(mod->ctx);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007536 return -1;
7537 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007538 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007539 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007540 LOGINT(mod->ctx);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007541 return -1;
7542 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007543 }
Michal Vaskodad19402015-08-06 09:51:53 +02007544
7545 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007546}
7547
Michal Vaskof02e3742015-08-05 16:27:02 +02007548/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007549int
Michal Vasko878e38d2016-09-05 12:17:53 +02007550unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007551{
Michal Vasko878e38d2016-09-05 12:17:53 +02007552 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007553 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007554
Michal Vaskoc643f712018-09-14 08:26:13 +02007555 if (!unres->count) {
7556 return -1;
7557 }
7558
Radek Krejciddddd0d2017-01-20 15:20:46 +01007559 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007560 i = start_on_backwards;
7561 } else {
7562 i = unres->count - 1;
7563 }
7564 for (; i > -1; i--) {
7565 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007566 continue;
7567 }
7568 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007569 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007570 break;
7571 }
7572 } else {
7573 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7574 aux_uniq2 = (struct unres_list_uniq *)item;
7575 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007576 break;
7577 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007578 }
7579 }
7580
Michal Vasko878e38d2016-09-05 12:17:53 +02007581 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007582}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007583
Michal Vaskoede9c472016-06-07 09:38:15 +02007584static void
7585unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7586{
7587 struct lyxml_elem *yin;
7588 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007589 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007590
7591 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007592 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007593 case UNRES_TYPE_DER:
7594 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7595 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7596 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007597 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007598 lydict_remove(ctx, yang->name);
7599 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007600 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7601 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7602 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007603 } else {
7604 lyxml_free(ctx, yin);
7605 }
7606 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007607 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007608 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7609 lydict_remove(ctx, iff_data->fname);
7610 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007611 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007612 case UNRES_IDENT:
7613 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007614 case UNRES_CHOICE_DFLT:
7615 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007616 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7617 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007618 case UNRES_LIST_UNIQ:
7619 free(unres->item[i]);
7620 break;
PavolVicanc1807262017-01-31 18:00:27 +01007621 case UNRES_EXT:
7622 free(unres->str_snode[i]);
7623 break;
PavolVicanfcc98762017-09-01 15:51:39 +02007624 case UNRES_EXT_FINALIZE:
7625 free(unres->str_snode[i]);
Michal Vaskoede9c472016-06-07 09:38:15 +02007626 default:
7627 break;
7628 }
7629 unres->type[i] = UNRES_RESOLVED;
7630}
7631
Michal Vasko88c29542015-11-27 14:57:53 +01007632void
Michal Vasko44ab1462017-05-18 13:18:36 +02007633unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007634{
7635 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007636 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007637
Radek Krejcic071c542016-01-27 14:57:51 +01007638 if (!unres || !(*unres)) {
7639 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007640 }
7641
Michal Vasko44ab1462017-05-18 13:18:36 +02007642 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007643
7644 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007645 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007646 if ((*unres)->type[i] != UNRES_RESOLVED) {
7647 unresolved++;
7648 }
7649 continue;
7650 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007651
7652 /* free heap memory for the specific item */
7653 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007654 }
7655
Michal Vaskoede9c472016-06-07 09:38:15 +02007656 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007657 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007658 free((*unres)->item);
7659 free((*unres)->type);
7660 free((*unres)->str_snode);
7661 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007662 free((*unres));
7663 (*unres) = NULL;
7664 }
Michal Vasko88c29542015-11-27 14:57:53 +01007665}
7666
Michal Vaskoff690e72017-08-03 14:25:07 +02007667/* check whether instance-identifier points outside its data subtree (for operation it is any node
7668 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007669static int
7670check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7671{
Michal Vaskoff690e72017-08-03 14:25:07 +02007672 const struct lys_node *op_node, *first_node;
Michal Vasko53b7da02018-02-13 15:28:42 +01007673 enum int_log_opts prev_ilo;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007674 char *buf;
Michal Vasko53b7da02018-02-13 15:28:42 +01007675 int ret = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007676
Radek Krejci034cb102017-08-01 15:45:13 +02007677 if (!json_instid || !json_instid[0]) {
7678 /* no/empty value */
7679 return 0;
7680 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007681
7682 for (op_node = lys_parent(sleaf);
7683 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7684 op_node = lys_parent(op_node));
7685
7686 if (op_node && lys_parent(op_node)) {
7687 /* nested operation - any absolute path is external */
7688 return 1;
7689 }
7690
7691 /* get the first node from the instid */
7692 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7693 if (!buf) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007694 /* so that we do not have to bother with logging, say it is not external */
7695 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007696 }
7697
Michal Vaskoff690e72017-08-03 14:25:07 +02007698 /* find the first schema node, do not log */
Michal Vasko53b7da02018-02-13 15:28:42 +01007699 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoff690e72017-08-03 14:25:07 +02007700 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
Michal Vasko53b7da02018-02-13 15:28:42 +01007701 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007702
Michal Vasko53b7da02018-02-13 15:28:42 +01007703 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007704 if (!first_node) {
7705 /* unknown path, say it is not external */
Michal Vaskoff690e72017-08-03 14:25:07 +02007706 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007707 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007708
7709 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7710
Michal Vaskoff690e72017-08-03 14:25:07 +02007711 if (op_node && (op_node != first_node)) {
7712 /* it is a top-level operation, so we're good if it points somewhere inside it */
7713 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007714 }
7715
7716 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7717 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007718 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007719}
7720
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007721/**
7722 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7723 *
7724 * @param[in] data Data node where the path is used
7725 * @param[in] path Instance-identifier node value.
7726 * @param[in,out] ret Resolved instance or NULL.
7727 *
7728 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7729 */
7730static int
7731resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7732{
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007733 int i = 0, j, parsed, cur_idx;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007734 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007735 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007736 struct lyd_node *root, *node;
Radek Krejcidaa547a2017-09-22 15:56:27 +02007737 const char *model = NULL, *name;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007738 char *str;
7739 int mod_len, name_len, has_predicate;
7740 struct unres_data node_match;
7741
7742 memset(&node_match, 0, sizeof node_match);
7743 *ret = NULL;
7744
7745 /* we need root to resolve absolute path */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007746 for (root = data; root->parent; root = root->parent);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007747 /* we're still parsing it and the pointer is not correct yet */
Radek Krejci2c822ed2017-08-03 14:23:36 +02007748 if (root->prev) {
7749 for (; root->prev->next; root = root->prev);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007750 }
7751
7752 /* search for the instance node */
7753 while (path[i]) {
7754 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7755 if (j <= 0) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007756 LOGVAL(ctx, LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007757 goto error;
7758 }
7759 i += j;
7760
Michal Vasko1b6ca962017-08-03 14:23:09 +02007761 if (model) {
7762 str = strndup(model, mod_len);
7763 if (!str) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007764 LOGMEM(ctx);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007765 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007766 }
Radek Krejcidfb00d62017-09-06 09:39:35 +02007767 mod = ly_ctx_get_module(ctx, str, NULL, 1);
Michal Vasko1b6ca962017-08-03 14:23:09 +02007768 if (ctx->data_clb) {
7769 if (!mod) {
7770 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7771 } else if (!mod->implemented) {
7772 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7773 }
7774 }
7775 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007776
Michal Vasko1b6ca962017-08-03 14:23:09 +02007777 if (!mod || !mod->implemented || mod->disabled) {
7778 break;
7779 }
7780 } else if (!prev_mod) {
7781 /* first iteration and we are missing module name */
Michal Vaskoaf8ec362018-03-28 09:08:09 +02007782 LOGVAL(ctx, LYE_INELEM_LEN, LY_VLOG_LYD, data, name_len, name);
7783 LOGVAL(ctx, LYE_SPEC, LY_VLOG_PREV, NULL, "Instance-identifier is missing prefix in the first node.");
Michal Vasko1b6ca962017-08-03 14:23:09 +02007784 goto error;
7785 } else {
7786 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007787 }
7788
Radek Krejci2c822ed2017-08-03 14:23:36 +02007789 if (resolve_data(mod, name, name_len, root, &node_match)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007790 /* no instance exists */
7791 break;
7792 }
7793
7794 if (has_predicate) {
7795 /* we have predicate, so the current results must be list or leaf-list */
Radek Krejcidaa547a2017-09-22 15:56:27 +02007796 parsed = j = 0;
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007797 /* index of the current node (for lists with position predicates) */
7798 cur_idx = 1;
7799 while (j < (signed)node_match.count) {
7800 node = node_match.node[j];
7801 parsed = resolve_instid_predicate(mod, &path[i], &node, cur_idx);
7802 if (parsed < 1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007803 LOGVAL(ctx, LYE_INPRED, LY_VLOG_LYD, data, &path[i - parsed]);
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007804 goto error;
7805 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007806
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007807 if (!node) {
7808 /* current node does not satisfy the predicate */
7809 unres_data_del(&node_match, j);
7810 } else {
7811 ++j;
7812 }
7813 ++cur_idx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007814 }
Michal Vaskoa3ca4b92017-09-15 12:43:01 +02007815
7816 i += parsed;
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007817 } else if (node_match.count) {
7818 /* check that we are not addressing lists */
7819 for (j = 0; (unsigned)j < node_match.count; ++j) {
7820 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7821 unres_data_del(&node_match, j--);
7822 }
7823 }
7824 if (!node_match.count) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007825 LOGVAL(ctx, LYE_SPEC, LY_VLOG_LYD, data, "Instance identifier is missing list keys.");
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007826 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007827 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007828
7829 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007830 }
7831
7832 if (!node_match.count) {
7833 /* no instance exists */
7834 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007835 LOGVAL(ctx, LYE_NOREQINS, LY_VLOG_LYD, data, path);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007836 return EXIT_FAILURE;
7837 }
7838 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7839 return EXIT_SUCCESS;
7840 } else if (node_match.count > 1) {
7841 /* instance identifier must resolve to a single node */
Michal Vasko53b7da02018-02-13 15:28:42 +01007842 LOGVAL(ctx, LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007843 goto error;
7844 } else {
7845 /* we have required result, remember it and cleanup */
7846 *ret = node_match.node[0];
7847 free(node_match.node);
7848 return EXIT_SUCCESS;
7849 }
7850
7851error:
7852 /* cleanup */
7853 free(node_match.node);
7854 return -1;
7855}
7856
7857static int
7858resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007859{
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007860 struct lyxp_set xp_set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007861 uint32_t i;
7862
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007863 memset(&xp_set, 0, sizeof xp_set);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007864 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007865
Michal Vaskoca16cb32017-07-10 11:50:33 +02007866 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007867 if (lyxp_eval(path, (struct lyd_node *)leaf, LYXP_NODE_ELEM, lyd_node_module((struct lyd_node *)leaf), &xp_set, 0) != EXIT_SUCCESS) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007868 return -1;
7869 }
7870
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007871 if (xp_set.type == LYXP_SET_NODE_SET) {
7872 for (i = 0; i < xp_set.used; ++i) {
7873 if ((xp_set.val.nodes[i].type != LYXP_NODE_ELEM) || !(xp_set.val.nodes[i].node->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7874 continue;
7875 }
Michal Vaskoca16cb32017-07-10 11:50:33 +02007876
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007877 /* not that the value is already in canonical form since the parsers does the conversion,
7878 * so we can simply compare just the values */
7879 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)xp_set.val.nodes[i].node)->value_str, 1)) {
7880 /* we have the match */
7881 *ret = xp_set.val.nodes[i].node;
7882 break;
7883 }
Radek Krejci7de36cf2016-09-12 16:18:50 +02007884 }
7885 }
7886
Michal Vaskob5f9ffb2018-08-06 09:01:27 +02007887 lyxp_set_cast(&xp_set, LYXP_SET_EMPTY, (struct lyd_node *)leaf, NULL, 0);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007888
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007889 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007890 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007891 if (req_inst > -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01007892 LOGVAL(leaf->schema->module->ctx, LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007893 return EXIT_FAILURE;
7894 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007895 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 +02007896 }
7897 }
7898
7899 return EXIT_SUCCESS;
7900}
7901
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007902/* 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 +01007903int
7904resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7905 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007906{
Michal Vasko53b7da02018-02-13 15:28:42 +01007907 struct ly_ctx *ctx = leaf->schema->module->ctx;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007908 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007909 struct lyd_node *ret;
Michal Vasko53b7da02018-02-13 15:28:42 +01007910 enum int_log_opts prev_ilo;
7911 int found, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007912 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007913
7914 assert(type->base == LY_TYPE_UNION);
7915
Michal Vasko101658e2018-06-05 15:05:54 +02007916 if ((leaf->value_type == LY_TYPE_UNION) || ((leaf->value_type == LY_TYPE_INST) && (leaf->value_flags & LY_VALUE_UNRES))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007917 /* either NULL or instid previously converted to JSON */
Michal Vaskoc6cd3f02018-03-02 14:07:42 +01007918 json_val = lydict_insert(ctx, leaf->value.string, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007919 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007920
Michal Vaskofd6c6502017-01-06 12:15:41 +01007921 if (store) {
Michal Vasko7ba37442018-11-06 08:59:27 +01007922 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, &((struct lys_node_leaf *)leaf->schema)->type,
7923 NULL, NULL, NULL);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007924 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007925 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007926
7927 /* 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 +01007928 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007929
7930 t = NULL;
7931 found = 0;
7932 while ((t = lyp_get_next_union_type(type, t, &found))) {
7933 found = 0;
7934
7935 switch (t->base) {
7936 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007937 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7938 req_inst = -1;
7939 } else {
7940 req_inst = t->info.lref.req;
7941 }
7942
7943 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007944 if (store) {
7945 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7946 /* valid resolved */
7947 leaf->value.leafref = ret;
7948 leaf->value_type = LY_TYPE_LEAFREF;
7949 } else {
7950 /* valid unresolved */
Michal Vasko53b7da02018-02-13 15:28:42 +01007951 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vasko35f46a82018-05-30 10:44:11 +02007952 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007953 return -1;
7954 }
Michal Vasko53b7da02018-02-13 15:28:42 +01007955 ly_ilo_change(NULL, ILO_IGNORE, &prev_ilo, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007956 }
7957 }
7958
7959 success = 1;
7960 }
7961 break;
7962 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007963 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7964 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7965 req_inst = -1;
7966 } else {
7967 req_inst = t->info.inst.req;
7968 }
7969
Michal Vaskod3a03112017-01-23 09:56:02 +01007970 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007971 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007972 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007973 /* valid resolved */
7974 leaf->value.instance = ret;
7975 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007976
Michal Vaskofd6c6502017-01-06 12:15:41 +01007977 if (json_val) {
7978 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7979 leaf->value_str = json_val;
7980 json_val = NULL;
7981 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007982 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007983 /* valid unresolved */
7984 if (json_val) {
7985 /* put the JSON val back */
7986 leaf->value.string = json_val;
7987 json_val = NULL;
7988 } else {
7989 leaf->value.instance = NULL;
7990 }
Michal Vasko70bf8e52018-03-26 11:32:33 +02007991 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02007992 leaf->value_flags |= LY_VALUE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007993 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007994 }
7995
7996 success = 1;
7997 }
7998 break;
7999 default:
Michal Vasko35f46a82018-05-30 10:44:11 +02008000 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, NULL, store, 0, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008001 success = 1;
8002 }
8003 break;
8004 }
8005
8006 if (success) {
8007 break;
8008 }
8009
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008010 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01008011 if (store) {
Michal Vasko7ba37442018-11-06 08:59:27 +01008012 lyd_free_value(leaf->value, leaf->value_type, leaf->value_flags, t, NULL, NULL, NULL);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008013 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008014 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008015 }
8016
8017 /* turn logging back on */
Michal Vasko53b7da02018-02-13 15:28:42 +01008018 ly_ilo_restore(NULL, prev_ilo, NULL, 0);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008019
8020 if (json_val) {
8021 if (!success) {
8022 /* put the value back for now */
8023 assert(leaf->value_type == LY_TYPE_UNION);
8024 leaf->value.string = json_val;
8025 } else {
8026 /* value was ultimately useless, but we could not have known */
8027 lydict_remove(leaf->schema->module->ctx, json_val);
8028 }
8029 }
8030
Michal Vaskofd6c6502017-01-06 12:15:41 +01008031 if (success) {
8032 if (resolved_type) {
8033 *resolved_type = t;
8034 }
8035 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008036 /* not found and it is required */
Michal Vasko53b7da02018-02-13 15:28:42 +01008037 LOGVAL(ctx, LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02008038 return EXIT_FAILURE;
8039 }
8040
8041 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008042
Radek Krejci9b6aad22016-09-20 15:55:51 +02008043}
8044
Michal Vasko8bcdf292015-08-19 14:04:43 +02008045/**
8046 * @brief Resolve a single unres data item. Logs directly.
8047 *
Michal Vaskocf024702015-10-08 15:01:42 +02008048 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02008049 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01008050 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008051 *
8052 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
8053 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02008054int
Michal Vasko0b963112017-08-11 12:45:36 +02008055resolve_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 +02008056{
Michal Vasko3cfa3182017-01-17 10:00:58 +01008057 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02008058 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008059 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008060 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008061
Michal Vasko83a6c462015-10-08 16:43:53 +02008062 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02008063 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008064
Michal Vaskocf024702015-10-08 15:01:42 +02008065 switch (type) {
8066 case UNRES_LEAFREF:
8067 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008068 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01008069 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
8070 req_inst = -1;
8071 } else {
8072 req_inst = sleaf->type.info.lref.req;
8073 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008074 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
8075 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01008076 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008077 /* valid resolved */
Michal Vasko70bf8e52018-03-26 11:32:33 +02008078 if (leaf->value_type == LY_TYPE_BITS) {
Michal Vasko1c8567a2017-01-05 13:42:27 +01008079 free(leaf->value.bit);
8080 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008081 leaf->value.leafref = ret;
8082 leaf->value_type = LY_TYPE_LEAFREF;
Michal Vasko101658e2018-06-05 15:05:54 +02008083 leaf->value_flags &= ~LY_VALUE_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008084 } else {
8085 /* valid unresolved */
Michal Vasko101658e2018-06-05 15:05:54 +02008086 if (!(leaf->value_flags & LY_VALUE_UNRES)) {
Michal Vasko35f46a82018-05-30 10:44:11 +02008087 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, NULL, 1, 0, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008088 return -1;
8089 }
8090 }
8091 }
8092 leaf->validity &= ~LYD_VAL_LEAFREF;
8093 } else {
8094 return rc;
8095 }
8096 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008097
Michal Vaskocf024702015-10-08 15:01:42 +02008098 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02008099 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01008100 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
8101 if (ext_dep == -1) {
8102 return -1;
8103 }
8104
8105 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
8106 req_inst = -1;
8107 } else {
8108 req_inst = sleaf->type.info.inst.req;
8109 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008110 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
8111 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008112 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008113 /* valid resolved */
8114 leaf->value.instance = ret;
8115 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02008116 leaf->value_flags &= ~LY_VALUE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008117 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008118 /* valid unresolved */
8119 leaf->value.instance = NULL;
Michal Vasko70bf8e52018-03-26 11:32:33 +02008120 leaf->value_type = LY_TYPE_INST;
Michal Vasko101658e2018-06-05 15:05:54 +02008121 leaf->value_flags |= LY_VALUE_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008122 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008123 } else {
8124 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008125 }
Michal Vaskocf024702015-10-08 15:01:42 +02008126 break;
8127
Radek Krejci7de36cf2016-09-12 16:18:50 +02008128 case UNRES_UNION:
8129 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01008130 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02008131
Michal Vaskocf024702015-10-08 15:01:42 +02008132 case UNRES_WHEN:
Michal Vasko0b963112017-08-11 12:45:36 +02008133 if ((rc = resolve_when(node, ignore_fail, failed_when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02008134 return rc;
8135 }
8136 break;
8137
Michal Vaskobf19d252015-10-08 15:39:17 +02008138 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008139 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02008140 return rc;
8141 }
8142 break;
8143
8144 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008145 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02008146 return rc;
8147 }
8148 break;
8149
Michal Vasko185b5272018-09-13 14:26:12 +02008150 case UNRES_UNIQ_LEAVES:
8151 if (lyv_data_unique(node)) {
8152 return -1;
8153 }
8154 break;
8155
Michal Vaskocf024702015-10-08 15:01:42 +02008156 default:
Michal Vasko53b7da02018-02-13 15:28:42 +01008157 LOGINT(NULL);
Michal Vasko8bcdf292015-08-19 14:04:43 +02008158 return -1;
8159 }
8160
8161 return EXIT_SUCCESS;
8162}
8163
8164/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01008165 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02008166 *
8167 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02008168 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008169 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01008170 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008171 */
8172int
Radek Krejci0b7704f2016-03-18 12:16:14 +01008173unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02008174{
Radek Krejci03b71f72016-03-16 11:10:09 +01008175 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02008176 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vasko185b5272018-09-13 14:26:12 +02008177 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_UNIQ_LEAVES));
Michal Vasko8bcdf292015-08-19 14:04:43 +02008178
Radek Krejci03b71f72016-03-16 11:10:09 +01008179 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01008180 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Michal Vasko53b7da02018-02-13 15:28:42 +01008181 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008182 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01008183 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Michal Vasko53b7da02018-02-13 15:28:42 +01008184 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM(NULL), -1);
Michal Vaskocf024702015-10-08 15:01:42 +02008185 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008186
Michal Vasko53b7da02018-02-13 15:28:42 +01008187 return 0;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008188}
8189
8190/**
8191 * @brief Resolve every unres data item in the structure. Logs directly.
8192 *
Michal Vasko660582a2018-03-19 10:10:08 +01008193 * If options include #LYD_OPT_TRUSTED, the data are considered trusted (must conditions are not expected,
8194 * unresolved leafrefs/instids are accepted, when conditions are normally resolved because at least some implicit
8195 * non-presence containers may need to be deleted).
Radek Krejci082c84f2016-10-17 16:33:06 +02008196 *
Michal Vaskobbc43b12018-10-12 09:22:00 +02008197 * If options includes #LYD_OPT_WHENAUTODEL, the non-default nodes with false when conditions are auto-deleted.
Radek Krejci082c84f2016-10-17 16:33:06 +02008198 *
Michal Vasko53b7da02018-02-13 15:28:42 +01008199 * @param[in] ctx Context used.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008200 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02008201 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
8202 * @param[in] options Data options as described above.
Michal Vasko8bcdf292015-08-19 14:04:43 +02008203 *
8204 * @return EXIT_SUCCESS on success, -1 on error.
8205 */
8206int
Michal Vasko53b7da02018-02-13 15:28:42 +01008207resolve_unres_data(struct ly_ctx *ctx, struct unres_data *unres, struct lyd_node **root, int options)
Michal Vasko8bcdf292015-08-19 14:04:43 +02008208{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008209 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko8af82202018-11-14 11:21:01 +01008210 uint8_t prev_when_status;
Michal Vasko3cfa3182017-01-17 10:00:58 +01008211 int rc, progress, ignore_fail;
Michal Vasko53b7da02018-02-13 15:28:42 +01008212 enum int_log_opts prev_ilo;
8213 struct ly_err_item *prev_eitem;
mohitarora2489837dc2018-05-01 15:09:36 +05308214 LY_ERR prev_ly_errno = ly_errno;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008215 struct lyd_node *parent;
Michal Vasko0b963112017-08-11 12:45:36 +02008216 struct lys_when *when;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008217
Radek Krejci082c84f2016-10-17 16:33:06 +02008218 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01008219 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01008220
8221 if (!unres->count) {
8222 return EXIT_SUCCESS;
8223 }
Michal Vasko8bcdf292015-08-19 14:04:43 +02008224
Michal Vasko7fa93142018-03-19 09:59:10 +01008225 if (options & (LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008226 ignore_fail = 1;
8227 } else if (options & LYD_OPT_NOEXTDEPS) {
8228 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008229 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01008230 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008231 }
8232
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008233 LOGVRB("Resolving unresolved data nodes and their constraints...");
Michal Vasko7fa93142018-03-19 09:59:10 +01008234 if (!ignore_fail) {
8235 /* remember logging state only if errors are generated and valid */
Michal Vasko7fa93142018-03-19 09:59:10 +01008236 ly_ilo_change(ctx, ILO_STORE, &prev_ilo, &prev_eitem);
8237 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008238
Michal Vasko7fa93142018-03-19 09:59:10 +01008239 /*
8240 * when-stmt first
8241 */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008242 first = 1;
8243 stmt_count = 0;
8244 resolved = 0;
8245 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01008246 do {
Michal Vasko7fa93142018-03-19 09:59:10 +01008247 if (!ignore_fail) {
8248 ly_err_free_next(ctx, prev_eitem);
8249 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008250 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02008251 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008252 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008253 continue;
8254 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008255 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008256 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008257 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008258 }
8259
8260 /* resolve when condition only when all parent when conditions are already resolved */
8261 for (parent = unres->node[i]->parent;
8262 parent && LYD_WHEN_DONE(parent->when_status);
8263 parent = parent->parent) {
8264 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
8265 /* the parent node was already unlinked, do not resolve this node,
Michal Vaskoe446b092017-08-11 10:58:09 +02008266 * it will be removed anyway, so just mark it as resolved
Radek Krejci0b7704f2016-03-18 12:16:14 +01008267 */
8268 unres->node[i]->when_status |= LYD_WHEN_FALSE;
8269 unres->type[i] = UNRES_RESOLVED;
8270 resolved++;
8271 break;
8272 }
8273 }
8274 if (parent) {
8275 continue;
8276 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008277
Michal Vasko8af82202018-11-14 11:21:01 +01008278 prev_when_status = unres->node[i]->when_status;
Michal Vasko0b963112017-08-11 12:45:36 +02008279 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, &when);
Radek Krejci010e54b2016-03-15 09:40:34 +01008280 if (!rc) {
Michal Vasko8af82202018-11-14 11:21:01 +01008281 /* finish with error/delete the node only if when was changed from true to false, an external
8282 * dependency was not required, or it was not provided (the flag would not be passed down otherwise,
8283 * checked in upper functions) */
Michal Vaskoe446b092017-08-11 10:58:09 +02008284 if ((unres->node[i]->when_status & LYD_WHEN_FALSE)
Michal Vaskoc04173b2018-03-09 10:43:22 +01008285 && (!(when->flags & (LYS_XPCONF_DEP | LYS_XPSTATE_DEP)) || !(options & LYD_OPT_NOEXTDEPS))) {
Michal Vasko8af82202018-11-14 11:21:01 +01008286 if ((!(prev_when_status & LYD_WHEN_TRUE) || !(options & LYD_OPT_WHENAUTODEL)) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01008287 /* false when condition */
Michal Vasko53b7da02018-02-13 15:28:42 +01008288 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008289 } /* follows else */
8290
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008291 /* auto-delete */
Michal Vasko8af82202018-11-14 11:21:01 +01008292 LOGVRB("Auto-deleting node \"%s\" due to when condition (%s)", ly_errpath(ctx), when->cond);
Michal Vaskoe31d34a2017-03-28 14:50:38 +02008293
Radek Krejci0c0086a2016-03-24 15:20:28 +01008294 /* only unlink now, the subtree can contain another nodes stored in the unres list */
8295 /* if it has parent non-presence containers that would be empty, we should actually
8296 * remove the container
8297 */
Radek Krejci2537fd32016-09-07 16:22:41 +02008298 for (parent = unres->node[i];
8299 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
8300 parent = parent->parent) {
8301 if (((struct lys_node_container *)parent->parent->schema)->presence) {
8302 /* presence container */
8303 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008304 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008305 if (parent->next || parent->prev != parent) {
8306 /* non empty (the child we are in and we are going to remove is not the only child) */
8307 break;
8308 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008309 }
Radek Krejci2537fd32016-09-07 16:22:41 +02008310 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01008311
Radek Krejci0c0086a2016-03-24 15:20:28 +01008312 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01008313 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01008314 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008315
Radek Krejci0b7704f2016-03-18 12:16:14 +01008316 lyd_unlink(unres->node[i]);
8317 unres->type[i] = UNRES_DELETE;
8318 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01008319
8320 /* update the rest of unres items */
8321 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01008322 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01008323 continue;
8324 }
8325
8326 /* test if the node is in subtree to be deleted */
8327 for (parent = unres->node[j]; parent; parent = parent->parent) {
8328 if (parent == unres->node[i]) {
8329 /* yes, it is */
8330 unres->type[j] = UNRES_RESOLVED;
8331 resolved++;
8332 break;
8333 }
8334 }
8335 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01008336 } else {
8337 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01008338 }
Michal Vasko7fa93142018-03-19 09:59:10 +01008339 if (!ignore_fail) {
8340 ly_err_free_next(ctx, prev_eitem);
8341 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008342 resolved++;
8343 progress = 1;
8344 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008345 goto error;
Radek Krejci2467a492016-10-24 15:16:59 +02008346 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01008347 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008348 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008349 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01008350
Radek Krejci0b7704f2016-03-18 12:16:14 +01008351 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008352 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008353 goto error;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008354 }
8355
8356 for (i = 0; del_items && i < unres->count; i++) {
8357 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
8358 if (unres->type[i] != UNRES_DELETE) {
8359 continue;
8360 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01008361 if (!unres->node[i]) {
8362 unres->type[i] = UNRES_RESOLVED;
8363 del_items--;
8364 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01008365 }
8366
8367 /* really remove the complete subtree */
8368 lyd_free(unres->node[i]);
8369 unres->type[i] = UNRES_RESOLVED;
8370 del_items--;
8371 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008372
Michal Vasko7fa93142018-03-19 09:59:10 +01008373 /*
8374 * now leafrefs
8375 */
8376 if (options & LYD_OPT_TRUSTED) {
8377 /* we want to attempt to resolve leafrefs */
8378 assert(!ignore_fail);
8379 ignore_fail = 1;
8380
8381 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8382 ly_errno = prev_ly_errno;
8383 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008384 first = 1;
8385 stmt_count = 0;
8386 resolved = 0;
8387 do {
8388 progress = 0;
8389 for (i = 0; i < unres->count; i++) {
8390 if (unres->type[i] != UNRES_LEAFREF) {
8391 continue;
8392 }
8393 if (first) {
8394 /* count leafref nodes in unres list */
8395 stmt_count++;
8396 }
8397
Michal Vasko0b963112017-08-11 12:45:36 +02008398 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008399 if (!rc) {
8400 unres->type[i] = UNRES_RESOLVED;
Michal Vasko7fa93142018-03-19 09:59:10 +01008401 if (!ignore_fail) {
8402 ly_err_free_next(ctx, prev_eitem);
8403 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008404 resolved++;
8405 progress = 1;
8406 } else if (rc == -1) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008407 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008408 } /* else forward reference */
8409 }
8410 first = 0;
8411 } while (progress && resolved < stmt_count);
8412
8413 /* do we have some unresolved leafrefs? */
8414 if (stmt_count > resolved) {
Michal Vasko53b7da02018-02-13 15:28:42 +01008415 goto error;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02008416 }
8417
Michal Vasko7fa93142018-03-19 09:59:10 +01008418 if (!ignore_fail) {
8419 /* log normally now, throw away irrelevant errors */
8420 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 0);
8421 ly_errno = prev_ly_errno;
8422 }
Radek Krejci010e54b2016-03-15 09:40:34 +01008423
Michal Vasko7fa93142018-03-19 09:59:10 +01008424 /*
8425 * rest
8426 */
Michal Vasko8bcdf292015-08-19 14:04:43 +02008427 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01008428 if (unres->type[i] == UNRES_RESOLVED) {
8429 continue;
8430 }
Radek Krejci082c84f2016-10-17 16:33:06 +02008431 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01008432
Michal Vasko0b963112017-08-11 12:45:36 +02008433 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail, NULL);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008434 if (rc) {
8435 /* since when was already resolved, a forward reference is an error */
Michal Vasko8bcdf292015-08-19 14:04:43 +02008436 return -1;
8437 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01008438
8439 unres->type[i] = UNRES_RESOLVED;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008440 }
8441
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02008442 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01008443 unres->count = 0;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008444 return EXIT_SUCCESS;
Michal Vasko53b7da02018-02-13 15:28:42 +01008445
8446error:
Michal Vasko7fa93142018-03-19 09:59:10 +01008447 if (!ignore_fail) {
8448 /* print all the new errors */
8449 ly_ilo_restore(ctx, prev_ilo, prev_eitem, 1);
8450 /* do not restore ly_errno, it was udpated properly */
8451 }
Michal Vasko53b7da02018-02-13 15:28:42 +01008452 return -1;
Michal Vasko8bcdf292015-08-19 14:04:43 +02008453}