blob: 0e08ddd1e11dc9190da4970b14c28d2db34476b6 [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 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci54f6fb32016-02-24 12:56:39 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vasko8de098c2016-02-26 10:00:25 +010011 *
Radek Krejci54f6fb32016-02-24 12:56:39 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko730dfdf2015-08-11 14:48:05 +020013 */
14
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020015#define _GNU_SOURCE
16
17#include <stdlib.h>
18#include <assert.h>
19#include <string.h>
20#include <ctype.h>
Michal Vaskoe7fc19c2015-08-05 16:24:39 +020021#include <limits.h>
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020022
23#include "libyang.h"
24#include "resolve.h"
25#include "common.h"
Michal Vaskocf024702015-10-08 15:01:42 +020026#include "xpath.h"
Michal Vasko1dca6882015-10-22 14:29:42 +020027#include "parser.h"
Pavol Vicana0e4e672016-02-24 12:20:04 +010028#include "parser_yang.h"
Michal Vasko88c29542015-11-27 14:57:53 +010029#include "xml_internal.h"
Radek Krejci41912fe2015-10-22 10:22:12 +020030#include "dict_private.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020031#include "tree_internal.h"
Radek Krejcie534c132016-11-23 13:32:31 +010032#include "extensions.h"
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +020033
Michal Vaskod24dd012016-09-30 12:20:22 +020034int
35parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020036{
37 const char *ptr;
38 int minus = 0;
39 int64_t ret = 0;
Radek Krejcibf47a822016-11-04 10:06:08 +010040 int8_t str_exp, str_dig = -1, trailing_zeros = 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020041
42 ptr = *str_num;
43
44 if (ptr[0] == '-') {
45 minus = 1;
46 ++ptr;
Radek Krejci51673202016-11-01 17:00:32 +010047 } else if (ptr[0] == '+') {
48 ++ptr;
Michal Vasko4d1f0482016-09-19 14:35:06 +020049 }
50
Michal Vaskod24dd012016-09-30 12:20:22 +020051 if (!isdigit(ptr[0])) {
52 /* there must be at least one */
53 return 1;
54 }
55
Michal Vasko4d1f0482016-09-19 14:35:06 +020056 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
57 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020058 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020059 }
60
61 if (ptr[0] == '.') {
62 if (ptr[1] == '.') {
63 /* it's the next interval */
64 break;
65 }
66 ++str_dig;
67 } else {
Radek Krejcibf47a822016-11-04 10:06:08 +010068 ret = ret * 10 + (ptr[0] - '0');
Michal Vasko4d1f0482016-09-19 14:35:06 +020069 if (str_dig > -1) {
70 ++str_dig;
Radek Krejcibf47a822016-11-04 10:06:08 +010071 if (ptr[0] == '0') {
72 /* possibly trailing zero */
73 trailing_zeros++;
74 } else {
75 trailing_zeros = 0;
76 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020077 }
78 ++str_exp;
79 }
80 }
Michal Vaskod24dd012016-09-30 12:20:22 +020081 if (str_dig == 0) {
82 /* no digits after '.' */
83 return 1;
84 } else if (str_dig == -1) {
85 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020086 str_dig = 0;
87 }
Radek Krejcibf47a822016-11-04 10:06:08 +010088 /* remove trailing zeros */
89 if (trailing_zeros) {
Michal Vasko6ca5ca72016-11-28 09:21:51 +010090 str_dig -= trailing_zeros;
91 str_exp -= trailing_zeros;
Radek Krejcibf47a822016-11-04 10:06:08 +010092 ret = ret / dec_pow(trailing_zeros);
93 }
Michal Vasko4d1f0482016-09-19 14:35:06 +020094
95 /* it's parsed, now adjust the number based on fraction-digits, if needed */
96 if (str_dig < dig) {
97 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020098 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020099 }
100 ret *= dec_pow(dig - str_dig);
101 }
102 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +0200103 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200104 }
105
106 if (minus) {
107 ret *= -1;
108 }
109 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +0200110 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200111
Michal Vaskod24dd012016-09-30 12:20:22 +0200112 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +0200113}
114
115/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200116 * @brief Parse an identifier.
117 *
118 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
119 * identifier = (ALPHA / "_")
120 * *(ALPHA / DIGIT / "_" / "-" / ".")
121 *
Michal Vaskobb211122015-08-19 14:03:11 +0200122 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200123 *
124 * @return Number of characters successfully parsed.
125 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200126int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200127parse_identifier(const char *id)
128{
129 int parsed = 0;
130
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100131 assert(id);
132
Radek Krejci6dc53a22015-08-17 13:27:59 +0200133 if (!isalpha(id[0]) && (id[0] != '_')) {
134 return -parsed;
135 }
136
137 ++parsed;
138 ++id;
139
140 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
141 ++parsed;
142 ++id;
143 }
144
145 return parsed;
146}
147
148/**
149 * @brief Parse a node-identifier.
150 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200151 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200152 *
Michal Vaskobb211122015-08-19 14:03:11 +0200153 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200154 * @param[out] mod_name Points to the module name, NULL if there is not any.
155 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200156 * @param[out] name Points to the node name.
157 * @param[out] nam_len Length of the node name.
158 *
159 * @return Number of characters successfully parsed,
160 * positive on success, negative on failure.
161 */
162static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200163parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200164{
165 int parsed = 0, ret;
166
167 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200168 if (mod_name) {
169 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200170 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200171 if (mod_name_len) {
172 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200173 }
174 if (name) {
175 *name = NULL;
176 }
177 if (nam_len) {
178 *nam_len = 0;
179 }
180
181 if ((ret = parse_identifier(id)) < 1) {
182 return ret;
183 }
184
Michal Vasko723e50c2015-10-20 15:20:29 +0200185 if (mod_name) {
186 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200187 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200188 if (mod_name_len) {
189 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200190 }
191
192 parsed += ret;
193 id += ret;
194
195 /* there is prefix */
196 if (id[0] == ':') {
197 ++parsed;
198 ++id;
199
200 /* there isn't */
201 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200202 if (name && mod_name) {
203 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200204 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200205 if (mod_name) {
206 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200207 }
208
Michal Vasko723e50c2015-10-20 15:20:29 +0200209 if (nam_len && mod_name_len) {
210 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200211 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200212 if (mod_name_len) {
213 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200214 }
215
216 return parsed;
217 }
218
219 /* identifier (node name) */
220 if ((ret = parse_identifier(id)) < 1) {
221 return -parsed+ret;
222 }
223
224 if (name) {
225 *name = id;
226 }
227 if (nam_len) {
228 *nam_len = ret;
229 }
230
231 return parsed+ret;
232}
233
234/**
235 * @brief Parse a path-predicate (leafref).
236 *
237 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
238 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
239 *
Michal Vaskobb211122015-08-19 14:03:11 +0200240 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200241 * @param[out] prefix Points to the prefix, NULL if there is not any.
242 * @param[out] pref_len Length of the prefix, 0 if there is not any.
243 * @param[out] name Points to the node name.
244 * @param[out] nam_len Length of the node name.
245 * @param[out] path_key_expr Points to the path-key-expr.
246 * @param[out] pke_len Length of the path-key-expr.
247 * @param[out] has_predicate Flag to mark whether there is another predicate following.
248 *
249 * @return Number of characters successfully parsed,
250 * positive on success, negative on failure.
251 */
252static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200253parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
254 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200255{
256 const char *ptr;
257 int parsed = 0, ret;
258
259 assert(id);
260 if (prefix) {
261 *prefix = NULL;
262 }
263 if (pref_len) {
264 *pref_len = 0;
265 }
266 if (name) {
267 *name = NULL;
268 }
269 if (nam_len) {
270 *nam_len = 0;
271 }
272 if (path_key_expr) {
273 *path_key_expr = NULL;
274 }
275 if (pke_len) {
276 *pke_len = 0;
277 }
278 if (has_predicate) {
279 *has_predicate = 0;
280 }
281
282 if (id[0] != '[') {
283 return -parsed;
284 }
285
286 ++parsed;
287 ++id;
288
289 while (isspace(id[0])) {
290 ++parsed;
291 ++id;
292 }
293
294 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
295 return -parsed+ret;
296 }
297
298 parsed += ret;
299 id += ret;
300
301 while (isspace(id[0])) {
302 ++parsed;
303 ++id;
304 }
305
306 if (id[0] != '=') {
307 return -parsed;
308 }
309
310 ++parsed;
311 ++id;
312
313 while (isspace(id[0])) {
314 ++parsed;
315 ++id;
316 }
317
318 if ((ptr = strchr(id, ']')) == NULL) {
319 return -parsed;
320 }
321
322 --ptr;
323 while (isspace(ptr[0])) {
324 --ptr;
325 }
326 ++ptr;
327
328 ret = ptr-id;
329 if (path_key_expr) {
330 *path_key_expr = id;
331 }
332 if (pke_len) {
333 *pke_len = ret;
334 }
335
336 parsed += ret;
337 id += ret;
338
339 while (isspace(id[0])) {
340 ++parsed;
341 ++id;
342 }
343
344 assert(id[0] == ']');
345
346 if (id[1] == '[') {
347 *has_predicate = 1;
348 }
349
350 return parsed+1;
351}
352
353/**
354 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
355 * the ".." and the first node-identifier, other calls parse a single
356 * node-identifier each.
357 *
358 * path-key-expr = current-function-invocation *WSP "/" *WSP
359 * rel-path-keyexpr
360 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
361 * *(node-identifier *WSP "/" *WSP)
362 * node-identifier
363 *
Michal Vaskobb211122015-08-19 14:03:11 +0200364 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200365 * @param[out] prefix Points to the prefix, NULL if there is not any.
366 * @param[out] pref_len Length of the prefix, 0 if there is not any.
367 * @param[out] name Points to the node name.
368 * @param[out] nam_len Length of the node name.
369 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
370 * must not be changed between consecutive calls.
371 * @return Number of characters successfully parsed,
372 * positive on success, negative on failure.
373 */
374static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200375parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
376 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200377{
378 int parsed = 0, ret, par_times = 0;
379
380 assert(id);
381 assert(parent_times);
382 if (prefix) {
383 *prefix = NULL;
384 }
385 if (pref_len) {
386 *pref_len = 0;
387 }
388 if (name) {
389 *name = NULL;
390 }
391 if (nam_len) {
392 *nam_len = 0;
393 }
394
395 if (!*parent_times) {
396 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
397 if (strncmp(id, "current()", 9)) {
398 return -parsed;
399 }
400
401 parsed += 9;
402 id += 9;
403
404 while (isspace(id[0])) {
405 ++parsed;
406 ++id;
407 }
408
409 if (id[0] != '/') {
410 return -parsed;
411 }
412
413 ++parsed;
414 ++id;
415
416 while (isspace(id[0])) {
417 ++parsed;
418 ++id;
419 }
420
421 /* rel-path-keyexpr */
422 if (strncmp(id, "..", 2)) {
423 return -parsed;
424 }
425 ++par_times;
426
427 parsed += 2;
428 id += 2;
429
430 while (isspace(id[0])) {
431 ++parsed;
432 ++id;
433 }
434 }
435
436 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
437 *
438 * first parent reference with whitespaces already parsed
439 */
440 if (id[0] != '/') {
441 return -parsed;
442 }
443
444 ++parsed;
445 ++id;
446
447 while (isspace(id[0])) {
448 ++parsed;
449 ++id;
450 }
451
452 while (!strncmp(id, "..", 2) && !*parent_times) {
453 ++par_times;
454
455 parsed += 2;
456 id += 2;
457
458 while (isspace(id[0])) {
459 ++parsed;
460 ++id;
461 }
462
463 if (id[0] != '/') {
464 return -parsed;
465 }
466
467 ++parsed;
468 ++id;
469
470 while (isspace(id[0])) {
471 ++parsed;
472 ++id;
473 }
474 }
475
476 if (!*parent_times) {
477 *parent_times = par_times;
478 }
479
480 /* all parent references must be parsed at this point */
481 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
482 return -parsed+ret;
483 }
484
485 parsed += ret;
486 id += ret;
487
488 return parsed;
489}
490
491/**
492 * @brief Parse path-arg (leafref).
493 *
494 * path-arg = absolute-path / relative-path
495 * absolute-path = 1*("/" (node-identifier *path-predicate))
496 * relative-path = 1*(".." "/") descendant-path
497 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200498 * @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 +0200499 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200500 * @param[out] prefix Points to the prefix, NULL if there is not any.
501 * @param[out] pref_len Length of the prefix, 0 if there is not any.
502 * @param[out] name Points to the node name.
503 * @param[out] nam_len Length of the node name.
504 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
505 * must not be changed between consecutive calls. -1 if the
506 * path is relative.
507 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
508 *
509 * @return Number of characters successfully parsed,
510 * positive on success, negative on failure.
511 */
512static int
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200513parse_path_arg(struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
514 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200515{
516 int parsed = 0, ret, par_times = 0;
517
518 assert(id);
519 assert(parent_times);
520 if (prefix) {
521 *prefix = NULL;
522 }
523 if (pref_len) {
524 *pref_len = 0;
525 }
526 if (name) {
527 *name = NULL;
528 }
529 if (nam_len) {
530 *nam_len = 0;
531 }
532 if (has_predicate) {
533 *has_predicate = 0;
534 }
535
536 if (!*parent_times && !strncmp(id, "..", 2)) {
537 ++par_times;
538
539 parsed += 2;
540 id += 2;
541
542 while (!strncmp(id, "/..", 3)) {
543 ++par_times;
544
545 parsed += 3;
546 id += 3;
547 }
548 }
549
550 if (!*parent_times) {
551 if (par_times) {
552 *parent_times = par_times;
553 } else {
554 *parent_times = -1;
555 }
556 }
557
558 if (id[0] != '/') {
559 return -parsed;
560 }
561
562 /* skip '/' */
563 ++parsed;
564 ++id;
565
566 /* node-identifier ([prefix:]identifier) */
567 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
568 return -parsed-ret;
569 }
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200570 if (!(*prefix)) {
571 /* actually we always need prefix even it is not specified */
572 *prefix = lys_main_module(mod)->name;
573 *pref_len = strlen(*prefix);
574 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575
576 parsed += ret;
577 id += ret;
578
579 /* there is no predicate */
580 if ((id[0] == '/') || !id[0]) {
581 return parsed;
582 } else if (id[0] != '[') {
583 return -parsed;
584 }
585
586 if (has_predicate) {
587 *has_predicate = 1;
588 }
589
590 return parsed;
591}
592
593/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200594 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200595 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200596 *
597 * instance-identifier = 1*("/" (node-identifier *predicate))
598 *
Michal Vaskobb211122015-08-19 14:03:11 +0200599 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200600 * @param[out] model Points to the model name.
601 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200602 * @param[out] name Points to the node name.
603 * @param[out] nam_len Length of the node name.
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 Vaskof39142b2015-10-21 11:40:05 +0200610parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
611 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612{
613 int parsed = 0, ret;
614
Radek Krejci6dc53a22015-08-17 13:27:59 +0200615 if (has_predicate) {
616 *has_predicate = 0;
617 }
618
619 if (id[0] != '/') {
620 return -parsed;
621 }
622
623 ++parsed;
624 ++id;
625
Michal Vaskob2f40be2016-09-08 16:03:48 +0200626 if ((ret = parse_identifier(id)) < 1) {
627 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200628 }
629
Michal Vaskob2f40be2016-09-08 16:03:48 +0200630 *model = id;
631 *mod_len = ret;
632
Radek Krejci6dc53a22015-08-17 13:27:59 +0200633 parsed += ret;
634 id += ret;
635
Michal Vaskob2f40be2016-09-08 16:03:48 +0200636 if (id[0] != ':') {
637 return -parsed;
638 }
639
640 ++parsed;
641 ++id;
642
643 if ((ret = parse_identifier(id)) < 1) {
644 return ret;
645 }
646
647 *name = id;
648 *nam_len = ret;
649
650 parsed += ret;
651 id += ret;
652
Radek Krejci4967cb62016-09-14 16:40:28 +0200653 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200654 *has_predicate = 1;
655 }
656
657 return parsed;
658}
659
660/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200661 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200662 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200663 *
664 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
665 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
666 * ((DQUOTE string DQUOTE) /
667 * (SQUOTE string SQUOTE))
668 * pos = non-negative-integer-value
669 *
Michal Vaskobb211122015-08-19 14:03:11 +0200670 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200671 * @param[out] model Points to the model name.
672 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200673 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
674 * @param[out] nam_len Length of the node name.
675 * @param[out] value Value the node-identifier must have (string from the grammar),
676 * NULL if there is not any.
677 * @param[out] val_len Length of the value, 0 if there is not any.
678 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
679 *
680 * @return Number of characters successfully parsed,
681 * positive on success, negative on failure.
682 */
683static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200684parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
685 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686{
687 const char *ptr;
688 int parsed = 0, ret;
689 char quote;
690
691 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200692 if (model) {
693 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200694 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200695 if (mod_len) {
696 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200697 }
698 if (name) {
699 *name = NULL;
700 }
701 if (nam_len) {
702 *nam_len = 0;
703 }
704 if (value) {
705 *value = NULL;
706 }
707 if (val_len) {
708 *val_len = 0;
709 }
710 if (has_predicate) {
711 *has_predicate = 0;
712 }
713
714 if (id[0] != '[') {
715 return -parsed;
716 }
717
718 ++parsed;
719 ++id;
720
721 while (isspace(id[0])) {
722 ++parsed;
723 ++id;
724 }
725
726 /* pos */
727 if (isdigit(id[0])) {
728 if (name) {
729 *name = id;
730 }
731
732 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200733 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200734 }
735
736 while (isdigit(id[0])) {
737 ++parsed;
738 ++id;
739 }
740
741 if (nam_len) {
742 *nam_len = id-(*name);
743 }
744
Michal Vaskof2f28a12016-09-09 12:43:06 +0200745 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200746 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200747 if (id[0] == '.') {
748 if (name) {
749 *name = id;
750 }
751 if (nam_len) {
752 *nam_len = 1;
753 }
754
755 ++parsed;
756 ++id;
757
758 } else {
759 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
760 return -parsed+ret;
761 } else if (model && !*model) {
762 return -parsed;
763 }
764
765 parsed += ret;
766 id += ret;
767 }
768
769 while (isspace(id[0])) {
770 ++parsed;
771 ++id;
772 }
773
774 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200775 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200776 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200777
Radek Krejci6dc53a22015-08-17 13:27:59 +0200778 ++parsed;
779 ++id;
780
Michal Vaskof2f28a12016-09-09 12:43:06 +0200781 while (isspace(id[0])) {
782 ++parsed;
783 ++id;
784 }
785
786 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
787 if ((id[0] == '\"') || (id[0] == '\'')) {
788 quote = id[0];
789
790 ++parsed;
791 ++id;
792
793 if ((ptr = strchr(id, quote)) == NULL) {
794 return -parsed;
795 }
796 ret = ptr-id;
797
798 if (value) {
799 *value = id;
800 }
801 if (val_len) {
802 *val_len = ret;
803 }
804
805 parsed += ret+1;
806 id += ret+1;
807 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200808 return -parsed;
809 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200810 }
811
812 while (isspace(id[0])) {
813 ++parsed;
814 ++id;
815 }
816
817 if (id[0] != ']') {
818 return -parsed;
819 }
820
821 ++parsed;
822 ++id;
823
824 if ((id[0] == '[') && has_predicate) {
825 *has_predicate = 1;
826 }
827
828 return parsed;
829}
830
831/**
832 * @brief Parse schema-nodeid.
833 *
834 * schema-nodeid = absolute-schema-nodeid /
835 * descendant-schema-nodeid
836 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200837 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200838 * node-identifier
839 * absolute-schema-nodeid
840 *
Michal Vaskobb211122015-08-19 14:03:11 +0200841 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200842 * @param[out] mod_name Points to the module name, NULL if there is not any.
843 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200844 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200845 * @param[out] nam_len Length of the node name.
846 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
847 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100848 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
849 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200850 *
851 * @return Number of characters successfully parsed,
852 * positive on success, negative on failure.
853 */
Michal Vasko22448d32016-03-16 13:17:29 +0100854int
Michal Vasko723e50c2015-10-20 15:20:29 +0200855parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100856 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200857{
858 int parsed = 0, ret;
859
860 assert(id);
861 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200862 if (mod_name) {
863 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200864 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200865 if (mod_name_len) {
866 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200867 }
868 if (name) {
869 *name = NULL;
870 }
871 if (nam_len) {
872 *nam_len = 0;
873 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100874 if (has_predicate) {
875 *has_predicate = 0;
876 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200877
878 if (id[0] != '/') {
879 if (*is_relative != -1) {
880 return -parsed;
881 } else {
882 *is_relative = 1;
883 }
Michal Vasko48935352016-03-29 11:52:36 +0200884 if (!strncmp(id, "./", 2)) {
885 parsed += 2;
886 id += 2;
887 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200888 } else {
889 if (*is_relative == -1) {
890 *is_relative = 0;
891 }
892 ++parsed;
893 ++id;
894 }
895
Michal Vasko723e50c2015-10-20 15:20:29 +0200896 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200897 return -parsed+ret;
898 }
899
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100900 parsed += ret;
901 id += ret;
902
903 if ((id[0] == '[') && has_predicate) {
904 *has_predicate = 1;
905 }
906
907 return parsed;
908}
909
910/**
911 * @brief Parse schema predicate (special format internally used).
912 *
913 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko58c2aab2017-01-05 10:02:05 +0100914 * predicate-expr = "." / identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100915 * key-with-value = identifier *WSP "=" *WSP
916 * ((DQUOTE string DQUOTE) /
917 * (SQUOTE string SQUOTE))
918 *
919 * @param[in] id Identifier to use.
920 * @param[out] name Points to the list key name.
921 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100922 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100923 * @param[out] val_len Length of \p value.
924 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
925 */
Michal Vasko22448d32016-03-16 13:17:29 +0100926int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200927parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100928 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100929{
930 const char *ptr;
931 int parsed = 0, ret;
932 char quote;
933
934 assert(id);
935 if (name) {
936 *name = NULL;
937 }
938 if (nam_len) {
939 *nam_len = 0;
940 }
941 if (value) {
942 *value = NULL;
943 }
944 if (val_len) {
945 *val_len = 0;
946 }
947 if (has_predicate) {
948 *has_predicate = 0;
949 }
950
951 if (id[0] != '[') {
952 return -parsed;
953 }
954
955 ++parsed;
956 ++id;
957
958 while (isspace(id[0])) {
959 ++parsed;
960 ++id;
961 }
962
Michal Vasko22448d32016-03-16 13:17:29 +0100963 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200964 if (id[0] == '.') {
965 ret = 1;
Michal Vasko58c2aab2017-01-05 10:02:05 +0100966 } else if (isdigit(id[0])) {
967 if (id[0] == '0') {
968 return -parsed;
969 }
970 ret = 1;
971 while (isdigit(id[ret])) {
972 ++ret;
973 }
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200974 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100975 return -parsed + ret;
976 }
977 if (name) {
978 *name = id;
979 }
980 if (nam_len) {
981 *nam_len = ret;
982 }
983
984 parsed += ret;
985 id += ret;
986
987 while (isspace(id[0])) {
988 ++parsed;
989 ++id;
990 }
991
992 /* there is value as well */
993 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +0100994 if (name && isdigit(**name)) {
995 return -parsed;
996 }
997
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100998 ++parsed;
999 ++id;
1000
1001 while (isspace(id[0])) {
1002 ++parsed;
1003 ++id;
1004 }
1005
1006 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1007 if ((id[0] == '\"') || (id[0] == '\'')) {
1008 quote = id[0];
1009
1010 ++parsed;
1011 ++id;
1012
1013 if ((ptr = strchr(id, quote)) == NULL) {
1014 return -parsed;
1015 }
1016 ret = ptr - id;
1017
1018 if (value) {
1019 *value = id;
1020 }
1021 if (val_len) {
1022 *val_len = ret;
1023 }
1024
1025 parsed += ret + 1;
1026 id += ret + 1;
1027 } else {
1028 return -parsed;
1029 }
1030
1031 while (isspace(id[0])) {
1032 ++parsed;
1033 ++id;
1034 }
1035 }
1036
1037 if (id[0] != ']') {
1038 return -parsed;
1039 }
1040
1041 ++parsed;
1042 ++id;
1043
1044 if ((id[0] == '[') && has_predicate) {
1045 *has_predicate = 1;
1046 }
1047
1048 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001049}
1050
1051/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001052 * @brief Resolve (find) a feature definition. Logs directly.
1053 *
1054 * @param[in] feat_name Feature name to resolve.
1055 * @param[in] len Length of \p feat_name.
1056 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001057 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1058 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001059 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001060 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001061 */
1062static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001063resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001064{
1065 char *str;
1066 const char *mod_name, *name;
1067 int mod_name_len, nam_len, i, j;
1068 const struct lys_module *module;
1069
Radek Krejci9ff0a922016-07-14 13:08:05 +02001070 assert(feature);
1071
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001072 /* check prefix */
1073 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1074 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1075 return -1;
1076 }
1077
1078 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1079 if (!module) {
1080 /* identity refers unknown data model */
1081 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1082 return -1;
1083 }
1084
Radek Krejci9ff0a922016-07-14 13:08:05 +02001085 if (module != node->module && module == lys_node_module(node)) {
1086 /* first, try to search directly in submodule where the feature was mentioned */
1087 for (j = 0; j < node->module->features_size; j++) {
1088 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1089 /* check status */
1090 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001091 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001092 return -1;
1093 }
1094 *feature = &node->module->features[j];
1095 return 0;
1096 }
1097 }
1098 }
1099
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001100 /* search in the identified module ... */
1101 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001102 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001103 /* check status */
1104 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001105 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001106 return -1;
1107 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001108 *feature = &module->features[j];
1109 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001110 }
1111 }
1112 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001113 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001114 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001115 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1116 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117 /* check status */
1118 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1119 module->inc[i].submodule->features[j].flags,
1120 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001121 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001122 return -1;
1123 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001124 *feature = &module->inc[i].submodule->features[j];
1125 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 }
1127 }
1128 }
1129
1130 /* not found */
1131 str = strndup(feat_name, len);
1132 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1133 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001135}
1136
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137/*
1138 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001139 * - 1 if enabled
1140 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001141 * - -1 if not usable by its if-feature expression
1142 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001143static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001144resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001145{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001146 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001147
Radek Krejci9ff0a922016-07-14 13:08:05 +02001148 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001149 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001150 return -1;
1151 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001152 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001153
Radek Krejci69b8d922016-07-27 13:13:41 +02001154 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001155}
1156
1157static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001158resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001159{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001160 uint8_t op;
1161 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001162
Radek Krejci9ff0a922016-07-14 13:08:05 +02001163 op = iff_getop(expr->expr, *index_e);
1164 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001165
Radek Krejci9ff0a922016-07-14 13:08:05 +02001166 switch (op) {
1167 case LYS_IFF_F:
1168 /* resolve feature */
1169 return resolve_feature_value(expr->features[(*index_f)++]);
1170 case LYS_IFF_NOT:
1171 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1172 if (rc == -1) {
1173 /* one of the referenced feature is hidden by its if-feature,
1174 * so this if-feature expression is always false */
1175 return -1;
1176 } else {
1177 /* invert result */
1178 return rc ? 0 : 1;
1179 }
1180 case LYS_IFF_AND:
1181 case LYS_IFF_OR:
1182 a = resolve_iffeature_recursive(expr, index_e, index_f);
1183 b = resolve_iffeature_recursive(expr, index_e, index_f);
1184 if (a == -1 || b == -1) {
1185 /* one of the referenced feature is hidden by its if-feature,
1186 * so this if-feature expression is always false */
1187 return -1;
1188 } else if (op == LYS_IFF_AND) {
1189 return a && b;
1190 } else { /* LYS_IFF_OR */
1191 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001192 }
1193 }
1194
Radek Krejci9ff0a922016-07-14 13:08:05 +02001195 return -1;
1196}
1197
1198int
1199resolve_iffeature(struct lys_iffeature *expr)
1200{
1201 int rc = -1;
1202 int index_e = 0, index_f = 0;
1203
1204 if (expr->expr) {
1205 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1206 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001207 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001208}
1209
1210struct iff_stack {
1211 int size;
1212 int index; /* first empty item */
1213 uint8_t *stack;
1214};
1215
1216static int
1217iff_stack_push(struct iff_stack *stack, uint8_t value)
1218{
1219 if (stack->index == stack->size) {
1220 stack->size += 4;
1221 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1222 if (!stack->stack) {
1223 LOGMEM;
1224 stack->size = 0;
1225 return EXIT_FAILURE;
1226 }
1227 }
1228
1229 stack->stack[stack->index++] = value;
1230 return EXIT_SUCCESS;
1231}
1232
1233static uint8_t
1234iff_stack_pop(struct iff_stack *stack)
1235{
1236 stack->index--;
1237 return stack->stack[stack->index];
1238}
1239
1240static void
1241iff_stack_clean(struct iff_stack *stack)
1242{
1243 stack->size = 0;
1244 free(stack->stack);
1245}
1246
1247static void
1248iff_setop(uint8_t *list, uint8_t op, int pos)
1249{
1250 uint8_t *item;
1251 uint8_t mask = 3;
1252
1253 assert(pos >= 0);
1254 assert(op <= 3); /* max 2 bits */
1255
1256 item = &list[pos / 4];
1257 mask = mask << 2 * (pos % 4);
1258 *item = (*item) & ~mask;
1259 *item = (*item) | (op << 2 * (pos % 4));
1260}
1261
1262uint8_t
1263iff_getop(uint8_t *list, int pos)
1264{
1265 uint8_t *item;
1266 uint8_t mask = 3, result;
1267
1268 assert(pos >= 0);
1269
1270 item = &list[pos / 4];
1271 result = (*item) & (mask << 2 * (pos % 4));
1272 return result >> 2 * (pos % 4);
1273}
1274
1275#define LYS_IFF_LP 0x04 /* ( */
1276#define LYS_IFF_RP 0x08 /* ) */
1277
Radek Krejcicbb473e2016-09-16 14:48:32 +02001278/* internal structure for passing data for UNRES_IFFEAT */
1279struct unres_iffeat_data {
1280 struct lys_node *node;
1281 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001282 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001283};
1284
Radek Krejci9ff0a922016-07-14 13:08:05 +02001285void
1286resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1287{
1288 unsigned int e = 0, f = 0, r = 0;
1289 uint8_t op;
1290
1291 assert(iffeat);
1292
1293 if (!iffeat->expr) {
1294 goto result;
1295 }
1296
1297 do {
1298 op = iff_getop(iffeat->expr, e++);
1299 switch (op) {
1300 case LYS_IFF_NOT:
1301 if (!r) {
1302 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001303 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001304 break;
1305 case LYS_IFF_AND:
1306 case LYS_IFF_OR:
1307 if (!r) {
1308 r += 2;
1309 } else {
1310 r += 1;
1311 }
1312 break;
1313 case LYS_IFF_F:
1314 f++;
1315 if (r) {
1316 r--;
1317 }
1318 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001319 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001320 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001321
Radek Krejci9ff0a922016-07-14 13:08:05 +02001322result:
1323 if (expr_size) {
1324 *expr_size = e;
1325 }
1326 if (feat_size) {
1327 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001328 }
1329}
1330
1331int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001332resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001333 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001334{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001335 const char *c = value;
1336 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001337 int i, j, last_not, checkversion = 0;
1338 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001339 uint8_t op;
1340 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001341 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001342
Radek Krejci9ff0a922016-07-14 13:08:05 +02001343 assert(c);
1344
1345 if (isspace(c[0])) {
1346 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1347 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001348 }
1349
Radek Krejci9ff0a922016-07-14 13:08:05 +02001350 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1351 for (i = j = last_not = 0; c[i]; i++) {
1352 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001353 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001354 j++;
1355 continue;
1356 } else if (c[i] == ')') {
1357 j--;
1358 continue;
1359 } else if (isspace(c[i])) {
1360 continue;
1361 }
1362
1363 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1364 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001365 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001366 return EXIT_FAILURE;
1367 } else if (!isspace(c[i + r])) {
1368 /* feature name starting with the not/and/or */
1369 last_not = 0;
1370 f_size++;
1371 } else if (c[i] == 'n') { /* not operation */
1372 if (last_not) {
1373 /* double not */
1374 expr_size = expr_size - 2;
1375 last_not = 0;
1376 } else {
1377 last_not = 1;
1378 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001379 } else { /* and, or */
1380 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001381 /* not a not operation */
1382 last_not = 0;
1383 }
1384 i += r;
1385 } else {
1386 f_size++;
1387 last_not = 0;
1388 }
1389 expr_size++;
1390
1391 while (!isspace(c[i])) {
1392 if (!c[i] || c[i] == ')') {
1393 i--;
1394 break;
1395 }
1396 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001397 }
1398 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001399 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001400 /* not matching count of ( and ) */
1401 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1402 return EXIT_FAILURE;
1403 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001404
Radek Krejci69b8d922016-07-27 13:13:41 +02001405 if (checkversion || expr_size > 1) {
1406 /* check that we have 1.1 module */
1407 if (node->module->version != 2) {
1408 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1409 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1410 return EXIT_FAILURE;
1411 }
1412 }
1413
Radek Krejci9ff0a922016-07-14 13:08:05 +02001414 /* allocate the memory */
1415 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001416 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001417 stack.size = expr_size;
1418 stack.stack = malloc(expr_size * sizeof *stack.stack);
1419 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1420 LOGMEM;
1421 goto error;
1422 }
1423 f_size--; expr_size--; /* used as indexes from now */
1424
1425 for (i--; i >= 0; i--) {
1426 if (c[i] == ')') {
1427 /* push it on stack */
1428 iff_stack_push(&stack, LYS_IFF_RP);
1429 continue;
1430 } else if (c[i] == '(') {
1431 /* pop from the stack into result all operators until ) */
1432 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1433 iff_setop(iffeat_expr->expr, op, expr_size--);
1434 }
1435 continue;
1436 } else if (isspace(c[i])) {
1437 continue;
1438 }
1439
1440 /* end operator or operand -> find beginning and get what is it */
1441 j = i + 1;
1442 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1443 i--;
1444 }
1445 i++; /* get back by one step */
1446
1447 if (!strncmp(&c[i], "not ", 4)) {
1448 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1449 /* double not */
1450 iff_stack_pop(&stack);
1451 } else {
1452 /* not has the highest priority, so do not pop from the stack
1453 * as in case of AND and OR */
1454 iff_stack_push(&stack, LYS_IFF_NOT);
1455 }
1456 } else if (!strncmp(&c[i], "and ", 4)) {
1457 /* as for OR - pop from the stack all operators with the same or higher
1458 * priority and store them to the result, then push the AND to the stack */
1459 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1460 op = iff_stack_pop(&stack);
1461 iff_setop(iffeat_expr->expr, op, expr_size--);
1462 }
1463 iff_stack_push(&stack, LYS_IFF_AND);
1464 } else if (!strncmp(&c[i], "or ", 3)) {
1465 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1466 op = iff_stack_pop(&stack);
1467 iff_setop(iffeat_expr->expr, op, expr_size--);
1468 }
1469 iff_stack_push(&stack, LYS_IFF_OR);
1470 } else {
1471 /* feature name, length is j - i */
1472
1473 /* add it to the result */
1474 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1475
1476 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001477 * forward referenced, we have to keep the feature name in auxiliary
1478 * structure passed into unres */
1479 iff_data = malloc(sizeof *iff_data);
1480 iff_data->node = node;
1481 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001482 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001483 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1484 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001485 f_size--;
1486
1487 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001488 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001489 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001490 }
1491 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001492 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001493 while (stack.index) {
1494 op = iff_stack_pop(&stack);
1495 iff_setop(iffeat_expr->expr, op, expr_size--);
1496 }
1497
1498 if (++expr_size || ++f_size) {
1499 /* not all expected operators and operands found */
1500 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1501 rc = EXIT_FAILURE;
1502 } else {
1503 rc = EXIT_SUCCESS;
1504 }
1505
1506error:
1507 /* cleanup */
1508 iff_stack_clean(&stack);
1509
1510 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001511}
1512
1513/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001514 * @brief Resolve (find) a data node based on a schema-nodeid.
1515 *
1516 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1517 * module).
1518 *
1519 */
1520struct lyd_node *
1521resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1522{
1523 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001524 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001525 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001526 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001527
1528 assert(nodeid && start);
1529
1530 if (nodeid[0] == '/') {
1531 return NULL;
1532 }
1533
1534 str = p = strdup(nodeid);
1535 if (!str) {
1536 LOGMEM;
1537 return NULL;
1538 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001539
Michal Vasko3edeaf72016-02-11 13:17:43 +01001540 while (p) {
1541 token = p;
1542 p = strchr(p, '/');
1543 if (p) {
1544 *p = '\0';
1545 p++;
1546 }
1547
Radek Krejci5da4eb62016-04-08 14:45:51 +02001548 if (p) {
1549 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001550 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001551 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001552 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001553 result = NULL;
1554 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001555 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001556
Radek Krejci5da4eb62016-04-08 14:45:51 +02001557 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1558 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001559 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001560 /* shorthand case */
1561 if (!shorthand) {
1562 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001563 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001564 continue;
1565 } else {
1566 shorthand = 0;
1567 if (schema->nodetype == LYS_LEAF) {
1568 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1569 result = NULL;
1570 break;
1571 }
1572 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001573 }
1574 } else {
1575 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001576 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1577 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001578 || !schema) {
1579 result = NULL;
1580 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001581 }
1582 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001583 LY_TREE_FOR(result ? result->child : start, iter) {
1584 if (iter->schema == schema) {
1585 /* move in data tree according to returned schema */
1586 result = iter;
1587 break;
1588 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001589 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001590 if (!iter) {
1591 /* instance not found */
1592 result = NULL;
1593 break;
1594 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001595 }
1596 free(str);
1597
1598 return result;
1599}
1600
Radek Krejcibdf92362016-04-08 14:43:34 +02001601/*
1602 * 0 - ok (done)
1603 * 1 - continue
1604 * 2 - break
1605 * -1 - error
1606 */
1607static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001608schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001609 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001610 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001611{
1612 const struct lys_module *prefix_mod;
1613
1614 /* module check */
1615 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001616 if (prefix_mod && implemented_mod) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001617 prefix_mod = lys_implemented_module(prefix_mod);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001618 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001619 if (!prefix_mod) {
1620 return -1;
1621 }
1622 if (prefix_mod != lys_node_module(sibling)) {
1623 return 1;
1624 }
1625
1626 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001627 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001628 if (*shorthand != -1) {
1629 *shorthand = *shorthand ? 0 : 1;
1630 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001631 }
1632
1633 /* the result node? */
1634 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001635 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001636 return 1;
1637 }
1638 return 0;
1639 }
1640
Radek Krejci3a130162016-11-07 16:21:20 +01001641 if (!(*shorthand)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001642 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001643 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001644 return -1;
1645 }
1646 *start = sibling->child;
1647 }
1648
1649 return 2;
1650}
1651
Radek Krejcidf46e222016-11-08 11:57:37 +01001652/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1
1653 * implement: 0 - do not change the implemented status of the affected modules, 1 - change implemented status of the affected modules
1654 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001655int
1656resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
Radek Krejcidf46e222016-11-08 11:57:37 +01001657 int implement, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001658{
Radek Krejcidf46e222016-11-08 11:57:37 +01001659 const char *name, *mod_name, *mod_name_prev, *id;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001660 const struct lys_node *sibling;
1661 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001662 int8_t shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001663 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001664 const struct lys_module *start_mod, *aux_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001665
1666 assert(nodeid && (start || module) && !(start && module) && ret);
1667
1668 id = nodeid;
1669
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001670 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001671 return ((id - nodeid) - r) + 1;
1672 }
1673 id += r;
1674
1675 if ((is_relative && !start) || (!is_relative && !module)) {
1676 return -1;
1677 }
1678
1679 /* descendant-schema-nodeid */
1680 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001681 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001682
1683 /* absolute-schema-nodeid */
1684 } else {
1685 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejcidf46e222016-11-08 11:57:37 +01001686 if (start_mod != lys_main_module(module) && start_mod && !start_mod->implemented) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001687 /* if the submodule augments the mainmodule (or in general a module augments
1688 * itself, we don't want to search for the implemented module but augments
1689 * the module anyway. But when augmenting another module, we need the implemented
1690 * revision of the module if any */
Radek Krejci2eee5c02016-12-06 19:18:05 +01001691 aux_mod = lys_implemented_module(start_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001692 if (!aux_mod->implemented && implement) {
1693 /* make the found module implemented */
1694 if (lys_set_implemented(aux_mod)) {
1695 return -1;
1696 }
1697 }
1698 start_mod = aux_mod;
1699 implement++;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001700 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001701 if (!start_mod) {
1702 return -1;
1703 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001704 start = start_mod->data;
1705 }
1706
1707 while (1) {
1708 sibling = NULL;
Radek Krejcidf46e222016-11-08 11:57:37 +01001709 mod_name_prev = mod_name;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001710 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1711 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1712 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001713 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001714 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
Radek Krejcidf46e222016-11-08 11:57:37 +01001715 implement, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001716 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001717 *ret = sibling;
1718 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001719 } else if (r == 1) {
1720 continue;
1721 } else if (r == 2) {
1722 break;
1723 } else {
1724 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001725 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726 }
1727 }
1728
1729 /* no match */
1730 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001731 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001732 return EXIT_SUCCESS;
1733 }
1734
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001735 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001736 return ((id - nodeid) - r) + 1;
1737 }
1738 id += r;
Radek Krejcidf46e222016-11-08 11:57:37 +01001739
1740 if ((mod_name && mod_name_prev && strncmp(mod_name, mod_name_prev, mod_name_len + 1)) ||
1741 (mod_name != mod_name_prev && (!mod_name || !mod_name_prev))) {
1742 /* we are getting into another module (augment) */
1743 if (implement) {
1744 /* we have to check that also target modules are implemented, if not, we have to change it */
1745 aux_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
1746 if (!aux_mod) {
1747 return -1;
1748 }
1749 if (!aux_mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01001750 aux_mod = lys_implemented_module(aux_mod);
Radek Krejcidf46e222016-11-08 11:57:37 +01001751 if (!aux_mod->implemented) {
1752 /* make the found module implemented */
1753 if (lys_set_implemented(aux_mod)) {
1754 return -1;
1755 }
1756 }
1757 }
1758 } else {
1759 /* we are not implementing the module itself, so the augments outside the module are ignored */
1760 *ret = NULL;
1761 return EXIT_SUCCESS;
1762 }
1763 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001764 }
1765
1766 /* cannot get here */
1767 LOGINT;
1768 return -1;
1769}
1770
Radek Krejcif3c71de2016-04-11 12:45:46 +02001771/* unique, refine,
1772 * >0 - unexpected char on position (ret - 1),
1773 * 0 - ok (but ret can still be NULL),
1774 * -1 - error,
1775 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001776int
1777resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001778 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001779{
1780 const char *name, *mod_name, *id;
1781 const struct lys_node *sibling;
1782 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001783 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001784 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001785 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001786
1787 assert(nodeid && start && ret);
1788 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1789
1790 id = nodeid;
1791 module = start->module;
1792
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001793 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001794 return ((id - nodeid) - r) + 1;
1795 }
1796 id += r;
1797
1798 if (!is_relative) {
1799 return -1;
1800 }
1801
1802 while (1) {
1803 sibling = NULL;
1804 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1805 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1806 /* name match */
1807 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001808 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001809 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001810 if (!(sibling->nodetype & ret_nodetype)) {
1811 /* wrong node type, too bad */
1812 continue;
1813 }
1814 *ret = sibling;
1815 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001816 } else if (r == 1) {
1817 continue;
1818 } else if (r == 2) {
1819 break;
1820 } else {
1821 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001822 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001823 }
1824 }
1825
1826 /* no match */
1827 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001828 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001829 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001830 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1831 *ret = NULL;
1832 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001833 }
1834
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001835 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001836 return ((id - nodeid) - r) + 1;
1837 }
1838 id += r;
1839 }
1840
1841 /* cannot get here */
1842 LOGINT;
1843 return -1;
1844}
1845
1846/* choice default */
1847int
1848resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1849{
1850 /* cannot actually be a path */
1851 if (strchr(nodeid, '/')) {
1852 return -1;
1853 }
1854
Radek Krejcif3c71de2016-04-11 12:45:46 +02001855 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001856}
1857
1858/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1859static int
1860resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1861{
1862 const struct lys_module *module;
1863 const char *mod_prefix, *name;
1864 int i, mod_prefix_len, nam_len;
1865
1866 /* parse the identifier, it must be parsed on one call */
1867 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1868 return -i + 1;
1869 }
1870
1871 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1872 if (!module) {
1873 return -1;
1874 }
1875 if (module != start->module) {
1876 start = module->data;
1877 }
1878
1879 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1880
1881 return EXIT_SUCCESS;
1882}
1883
1884int
1885resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1886 const struct lys_node **ret)
1887{
1888 const char *name, *mod_name, *id;
1889 const struct lys_node *sibling, *start;
1890 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001891 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001892 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001893
1894 assert(nodeid && module && ret);
1895 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1896
1897 id = nodeid;
1898 start = module->data;
1899
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001900 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001901 return ((id - nodeid) - r) + 1;
1902 }
1903 id += r;
1904
1905 if (is_relative) {
1906 return -1;
1907 }
1908
1909 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001910 if (!abs_start_mod) {
1911 return -1;
1912 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001913
1914 while (1) {
1915 sibling = NULL;
1916 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1917 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1918 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001919 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001920 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001921 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001922 if (!(sibling->nodetype & ret_nodetype)) {
1923 /* wrong node type, too bad */
1924 continue;
1925 }
1926 *ret = sibling;
1927 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001928 } else if (r == 1) {
1929 continue;
1930 } else if (r == 2) {
1931 break;
1932 } else {
1933 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001934 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001935 }
1936 }
1937
1938 /* no match */
1939 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001940 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 return EXIT_SUCCESS;
1942 }
1943
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001944 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001945 return ((id - nodeid) - r) + 1;
1946 }
1947 id += r;
1948 }
1949
1950 /* cannot get here */
1951 LOGINT;
1952 return -1;
1953}
1954
Michal Vaskoe733d682016-03-14 09:08:27 +01001955static int
Michal Vasko3547c532016-03-14 09:40:50 +01001956resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001957{
1958 const char *name;
1959 int nam_len, has_predicate, i;
1960
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001961 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1962 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001963 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001964 return -1;
1965 }
1966
1967 predicate += i;
1968 *parsed += i;
1969
Michal Vasko58c2aab2017-01-05 10:02:05 +01001970 if (!isdigit(name[0])) {
1971 for (i = 0; i < list->keys_size; ++i) {
1972 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1973 break;
1974 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001975 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001976
Michal Vasko58c2aab2017-01-05 10:02:05 +01001977 if (i == list->keys_size) {
1978 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
1979 return -1;
1980 }
Michal Vaskoe733d682016-03-14 09:08:27 +01001981 }
1982
1983 /* more predicates? */
1984 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001985 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001986 }
1987
1988 return 0;
1989}
1990
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001991/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001992const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001993resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001994{
Michal Vasko10728b52016-04-07 14:26:29 +02001995 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001996 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001997 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001998 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001999 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01002000 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002001
Michal Vasko3547c532016-03-14 09:40:50 +01002002 assert(nodeid && (ctx || start));
2003 if (!ctx) {
2004 ctx = start->module->ctx;
2005 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002006
2007 id = nodeid;
2008
Michal Vaskoe733d682016-03-14 09:08:27 +01002009 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002010 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002011 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002012 }
2013 id += r;
2014
2015 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002016 assert(start);
2017 start = start->child;
2018 if (!start) {
2019 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02002020 str = strndup(nodeid, (name + nam_len) - nodeid);
2021 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2022 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002023 return NULL;
2024 }
2025 module = start->module;
2026 } else {
2027 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002028 str = strndup(nodeid, (name + nam_len) - nodeid);
2029 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2030 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002031 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002032 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2033 LOGINT;
2034 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002035 }
2036
Michal Vasko971a3ca2016-04-01 13:09:29 +02002037 if (ly_buf_used && module_name[0]) {
2038 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2039 }
2040 ly_buf_used++;
2041
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002042 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002043 module_name[mod_name_len] = '\0';
2044 module = ly_ctx_get_module(ctx, module_name, NULL);
2045
2046 if (buf_backup) {
2047 /* return previous internal buffer content */
2048 strcpy(module_name, buf_backup);
2049 free(buf_backup);
2050 buf_backup = NULL;
2051 }
2052 ly_buf_used--;
2053
Michal Vasko3547c532016-03-14 09:40:50 +01002054 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002055 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2056 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2057 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002058 return NULL;
2059 }
2060 start = module->data;
2061
2062 /* now it's as if there was no module name */
2063 mod_name = NULL;
2064 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002065 }
2066
Michal Vaskoe733d682016-03-14 09:08:27 +01002067 prev_mod = module;
2068
Michal Vasko3edeaf72016-02-11 13:17:43 +01002069 while (1) {
2070 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002071 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2072 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002073 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002074 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002075 /* module check */
2076 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002077 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002078 LOGINT;
2079 return NULL;
2080 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002081
2082 if (ly_buf_used && module_name[0]) {
2083 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2084 }
2085 ly_buf_used++;
2086
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002087 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002088 module_name[mod_name_len] = '\0';
2089 /* will also find an augment module */
2090 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002091
2092 if (buf_backup) {
2093 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002094 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002095 free(buf_backup);
2096 buf_backup = NULL;
2097 }
2098 ly_buf_used--;
2099
Michal Vasko3edeaf72016-02-11 13:17:43 +01002100 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002101 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2102 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2103 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002104 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002105 }
2106 } else {
2107 prefix_mod = prev_mod;
2108 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002109 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002110 continue;
2111 }
2112
Michal Vaskoe733d682016-03-14 09:08:27 +01002113 /* do we have some predicates on it? */
2114 if (has_predicate) {
2115 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002116 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2117 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2118 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2119 return NULL;
2120 }
2121 } else if (sibling->nodetype == LYS_LIST) {
2122 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2123 return NULL;
2124 }
2125 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002126 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002127 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002128 }
2129 id += r;
2130 }
2131
Radek Krejcibdf92362016-04-08 14:43:34 +02002132 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002133 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002134 shorthand = ~shorthand;
2135 }
2136
Michal Vasko3edeaf72016-02-11 13:17:43 +01002137 /* the result node? */
2138 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002139 if (shorthand) {
2140 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002141 str = strndup(nodeid, (name + nam_len) - nodeid);
2142 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko51e5c582017-01-19 14:16:39 +01002143 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002144 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002145 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002146 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002147 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002148 }
2149
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002150 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002151 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002152 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002153 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002154 return NULL;
2155 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002156 start = sibling->child;
2157 }
2158
2159 /* update prev mod */
2160 prev_mod = start->module;
2161 break;
2162 }
2163 }
2164
2165 /* no match */
2166 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002167 str = strndup(nodeid, (name + nam_len) - nodeid);
2168 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2169 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002170 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002171 }
2172
Michal Vaskoe733d682016-03-14 09:08:27 +01002173 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002174 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002175 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002176 }
2177 id += r;
2178 }
2179
2180 /* cannot get here */
2181 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002182 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002183}
2184
Michal Vasko22448d32016-03-16 13:17:29 +01002185static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002186resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
2187 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002188{
Michal Vasko9ba34de2016-12-07 12:21:19 +01002189 const char *name, *value, *key_val;
Michal Vasko22448d32016-03-16 13:17:29 +01002190 int nam_len, val_len, has_predicate = 1, r;
2191 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002192 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002193
Radek Krejci61a86c62016-03-24 11:06:44 +01002194 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002195 assert(node->schema->nodetype == LYS_LIST);
2196
Michal Vasko53adfc72017-01-06 10:39:10 +01002197 /* is the predicate a number? */
2198 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2199 || !strncmp(name, ".", nam_len)) {
2200 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2201 return -1;
2202 }
2203
2204 if (isdigit(name[0])) {
2205 if (position == atoi(name)) {
2206 /* match */
2207 *parsed += r;
2208 return 0;
2209 } else {
2210 /* not a match */
2211 return 1;
2212 }
2213 }
2214
2215 if (!((struct lys_node_list *)node->schema)->keys_size) {
2216 /* no keys in schema - causes an error later */
2217 return 0;
2218 }
2219
Michal Vaskof29903d2016-04-18 13:13:10 +02002220 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002221 if (!key) {
2222 /* it is not a position, so we need a key for it to be a match */
2223 return 1;
2224 }
2225
2226 /* go through all the keys */
2227 i = 0;
2228 goto check_parsed_values;
2229
2230 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002231 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002232 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002233 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002234 }
2235
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002236 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2237 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002238 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002239 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002240 }
2241
Michal Vasko53adfc72017-01-06 10:39:10 +01002242check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002243 predicate += r;
2244 *parsed += r;
2245
Michal Vaskof29903d2016-04-18 13:13:10 +02002246 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002247 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002248 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002249 }
2250
Michal Vasko9ba34de2016-12-07 12:21:19 +01002251 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002252 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002253 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2254 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002255 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2256 } else {
2257 key_val = key->value_str;
2258 }
2259
Michal Vasko22448d32016-03-16 13:17:29 +01002260 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002261 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002262 return 1;
2263 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002264
2265 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002266 }
2267
2268 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002269 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002270 return -1;
2271 }
2272
2273 return 0;
2274}
2275
Radek Krejci45826012016-08-24 15:07:57 +02002276/**
2277 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2278 *
2279 * @param[in] nodeid Node data path to find
2280 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2281 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2282 * @param[out] parsed Number of characters processed in \p id
2283 * @return The closes parent (or the node itself) from the path
2284 */
Michal Vasko22448d32016-03-16 13:17:29 +01002285struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002286resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2287 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002288{
Michal Vasko10728b52016-04-07 14:26:29 +02002289 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002290 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002291 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002292 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002293 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002294 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002295 const struct lys_module *prefix_mod, *prev_mod;
2296 struct ly_ctx *ctx;
2297
2298 assert(nodeid && start && parsed);
2299
2300 ctx = start->schema->module->ctx;
2301 id = nodeid;
2302
2303 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002304 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002305 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002306 return NULL;
2307 }
2308 id += r;
2309 /* add it to parsed only after the data node was actually found */
2310 last_parsed = r;
2311
2312 if (is_relative) {
Michal Vasko1adc7242016-11-16 11:05:28 +01002313 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002314 start = start->child;
2315 } else {
2316 for (; start->parent; start = start->parent);
Michal Vasko1adc7242016-11-16 11:05:28 +01002317 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002318 }
2319
2320 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002321 list_instance_position = 0;
2322
Michal Vasko22448d32016-03-16 13:17:29 +01002323 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002324 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002325 if (lys_parent(sibling->schema)) {
2326 if (options & LYD_PATH_OPT_OUTPUT) {
2327 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002328 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002329 *parsed = -1;
2330 return NULL;
2331 }
2332 } else {
2333 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002334 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002335 *parsed = -1;
2336 return NULL;
2337 }
2338 }
2339 }
2340
Michal Vasko22448d32016-03-16 13:17:29 +01002341 /* name match */
2342 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2343
2344 /* module check */
2345 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002346 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002347 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002348 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002349 return NULL;
2350 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002351
2352 if (ly_buf_used && module_name[0]) {
2353 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2354 }
2355 ly_buf_used++;
2356
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002357 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002358 module_name[mod_name_len] = '\0';
2359 /* will also find an augment module */
2360 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002361
2362 if (buf_backup) {
2363 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002364 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002365 free(buf_backup);
2366 buf_backup = NULL;
2367 }
2368 ly_buf_used--;
2369
Michal Vasko22448d32016-03-16 13:17:29 +01002370 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002371 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2372 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2373 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002374 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002375 return NULL;
2376 }
2377 } else {
2378 prefix_mod = prev_mod;
2379 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002380 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002381 continue;
2382 }
2383
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002384 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002385 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002386 llist = (struct lyd_node_leaf_list *)sibling;
2387
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002388 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002389 if (has_predicate) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002390 if ((r = parse_schema_json_predicate(id, &pred_name, &pred_name_len, &llist_value, &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002391 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2392 *parsed = -1;
2393 return NULL;
2394 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002395 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2396 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2397 *parsed = -1;
2398 return NULL;
2399 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002400 } else {
2401 r = 0;
2402 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002403 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002404 }
2405 }
2406
Michal Vasko9ba34de2016-12-07 12:21:19 +01002407 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002408 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002409 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2410 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002411 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2412 } else {
2413 data_val = llist->value_str;
2414 }
2415
2416 if ((!llist_value && data_val && data_val[0])
2417 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002418 continue;
2419 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002420
Michal Vaskof0a50972016-10-19 11:33:55 +02002421 id += r;
2422 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002423 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002424
Radek Krejci45826012016-08-24 15:07:57 +02002425 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002426 /* list, we likely need predicates'n'stuff then, but if without a predicate, we are always creating it */
Michal Vasko22448d32016-03-16 13:17:29 +01002427 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002428 /* none match */
2429 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002430 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002431
2432 ++list_instance_position;
2433 r = 0;
2434 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002435 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002436 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002437 return NULL;
2438 } else if (ret == 1) {
2439 /* this list instance does not match */
2440 continue;
2441 }
2442 id += r;
2443 last_parsed += r;
2444 }
2445
2446 *parsed += last_parsed;
2447
2448 /* the result node? */
2449 if (!id[0]) {
2450 return sibling;
2451 }
2452
2453 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002454 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002455 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002456 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002457 return NULL;
2458 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002459 last_match = sibling;
Michal Vaskofc11b682016-11-18 09:52:41 +01002460 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002461 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002462 break;
2463 }
2464 }
2465
2466 /* no match, return last match */
2467 if (!sibling) {
2468 return last_match;
2469 }
2470
2471 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002472 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002473 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002474 return NULL;
2475 }
2476 id += r;
2477 last_parsed = r;
2478 }
2479
2480 /* cannot get here */
2481 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002482 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002483 return NULL;
2484}
2485
Michal Vasko3edeaf72016-02-11 13:17:43 +01002486/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002487 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002488 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002489 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002490 * @param[in] str_restr Restriction as a string.
2491 * @param[in] type Type of the restriction.
2492 * @param[out] ret Final interval structure that starts with
2493 * the interval of the initial type, continues with intervals
2494 * of any superior types derived from the initial one, and
2495 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002496 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002497 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002498 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002499int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002500resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002501{
2502 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002503 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002504 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002505 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002506 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002507 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002508 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002509
2510 switch (type->base) {
2511 case LY_TYPE_BINARY:
2512 kind = 0;
2513 local_umin = 0;
2514 local_umax = 18446744073709551615UL;
2515
2516 if (!str_restr && type->info.binary.length) {
2517 str_restr = type->info.binary.length->expr;
2518 }
2519 break;
2520 case LY_TYPE_DEC64:
2521 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002522 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2523 local_fmax = __INT64_C(9223372036854775807);
2524 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002525
2526 if (!str_restr && type->info.dec64.range) {
2527 str_restr = type->info.dec64.range->expr;
2528 }
2529 break;
2530 case LY_TYPE_INT8:
2531 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002532 local_smin = __INT64_C(-128);
2533 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002534
2535 if (!str_restr && type->info.num.range) {
2536 str_restr = type->info.num.range->expr;
2537 }
2538 break;
2539 case LY_TYPE_INT16:
2540 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002541 local_smin = __INT64_C(-32768);
2542 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002543
2544 if (!str_restr && type->info.num.range) {
2545 str_restr = type->info.num.range->expr;
2546 }
2547 break;
2548 case LY_TYPE_INT32:
2549 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002550 local_smin = __INT64_C(-2147483648);
2551 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002552
2553 if (!str_restr && type->info.num.range) {
2554 str_restr = type->info.num.range->expr;
2555 }
2556 break;
2557 case LY_TYPE_INT64:
2558 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002559 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2560 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002561
2562 if (!str_restr && type->info.num.range) {
2563 str_restr = type->info.num.range->expr;
2564 }
2565 break;
2566 case LY_TYPE_UINT8:
2567 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002568 local_umin = __UINT64_C(0);
2569 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570
2571 if (!str_restr && type->info.num.range) {
2572 str_restr = type->info.num.range->expr;
2573 }
2574 break;
2575 case LY_TYPE_UINT16:
2576 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002577 local_umin = __UINT64_C(0);
2578 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002579
2580 if (!str_restr && type->info.num.range) {
2581 str_restr = type->info.num.range->expr;
2582 }
2583 break;
2584 case LY_TYPE_UINT32:
2585 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002586 local_umin = __UINT64_C(0);
2587 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002588
2589 if (!str_restr && type->info.num.range) {
2590 str_restr = type->info.num.range->expr;
2591 }
2592 break;
2593 case LY_TYPE_UINT64:
2594 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002595 local_umin = __UINT64_C(0);
2596 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002597
2598 if (!str_restr && type->info.num.range) {
2599 str_restr = type->info.num.range->expr;
2600 }
2601 break;
2602 case LY_TYPE_STRING:
2603 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002604 local_umin = __UINT64_C(0);
2605 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002606
2607 if (!str_restr && type->info.str.length) {
2608 str_restr = type->info.str.length->expr;
2609 }
2610 break;
2611 default:
2612 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002613 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002614 }
2615
2616 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002617 if (type->der) {
2618 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002619 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002620 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002621 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002622 assert(!intv || (intv->kind == kind));
2623 }
2624
2625 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002626 /* we do not have any restriction, return superior ones */
2627 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002628 return EXIT_SUCCESS;
2629 }
2630
2631 /* adjust local min and max */
2632 if (intv) {
2633 tmp_intv = intv;
2634
2635 if (kind == 0) {
2636 local_umin = tmp_intv->value.uval.min;
2637 } else if (kind == 1) {
2638 local_smin = tmp_intv->value.sval.min;
2639 } else if (kind == 2) {
2640 local_fmin = tmp_intv->value.fval.min;
2641 }
2642
2643 while (tmp_intv->next) {
2644 tmp_intv = tmp_intv->next;
2645 }
2646
2647 if (kind == 0) {
2648 local_umax = tmp_intv->value.uval.max;
2649 } else if (kind == 1) {
2650 local_smax = tmp_intv->value.sval.max;
2651 } else if (kind == 2) {
2652 local_fmax = tmp_intv->value.fval.max;
2653 }
2654 }
2655
2656 /* finally parse our restriction */
2657 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002658 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002659 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002660 if (!tmp_local_intv) {
2661 assert(!local_intv);
2662 local_intv = malloc(sizeof *local_intv);
2663 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002665 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002666 tmp_local_intv = tmp_local_intv->next;
2667 }
Michal Vasko253035f2015-12-17 16:58:13 +01002668 if (!tmp_local_intv) {
2669 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002670 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002671 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002672
2673 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002674 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002675 tmp_local_intv->next = NULL;
2676
2677 /* min */
2678 ptr = seg_ptr;
2679 while (isspace(ptr[0])) {
2680 ++ptr;
2681 }
2682 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2683 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002684 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002685 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002686 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002687 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002688 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2689 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2690 goto error;
2691 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002692 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002693 } else if (!strncmp(ptr, "min", 3)) {
2694 if (kind == 0) {
2695 tmp_local_intv->value.uval.min = local_umin;
2696 } else if (kind == 1) {
2697 tmp_local_intv->value.sval.min = local_smin;
2698 } else if (kind == 2) {
2699 tmp_local_intv->value.fval.min = local_fmin;
2700 }
2701
2702 ptr += 3;
2703 } else if (!strncmp(ptr, "max", 3)) {
2704 if (kind == 0) {
2705 tmp_local_intv->value.uval.min = local_umax;
2706 } else if (kind == 1) {
2707 tmp_local_intv->value.sval.min = local_smax;
2708 } else if (kind == 2) {
2709 tmp_local_intv->value.fval.min = local_fmax;
2710 }
2711
2712 ptr += 3;
2713 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002714 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002715 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002716 }
2717
2718 while (isspace(ptr[0])) {
2719 ptr++;
2720 }
2721
2722 /* no interval or interval */
2723 if ((ptr[0] == '|') || !ptr[0]) {
2724 if (kind == 0) {
2725 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2726 } else if (kind == 1) {
2727 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2728 } else if (kind == 2) {
2729 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2730 }
2731 } else if (!strncmp(ptr, "..", 2)) {
2732 /* skip ".." */
2733 ptr += 2;
2734 while (isspace(ptr[0])) {
2735 ++ptr;
2736 }
2737
2738 /* max */
2739 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2740 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002741 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002742 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002743 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002744 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002745 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2746 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2747 goto error;
2748 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002749 }
2750 } else if (!strncmp(ptr, "max", 3)) {
2751 if (kind == 0) {
2752 tmp_local_intv->value.uval.max = local_umax;
2753 } else if (kind == 1) {
2754 tmp_local_intv->value.sval.max = local_smax;
2755 } else if (kind == 2) {
2756 tmp_local_intv->value.fval.max = local_fmax;
2757 }
2758 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002759 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002760 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002761 }
2762 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002763 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002764 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002765 }
2766
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002767 /* check min and max in correct order*/
2768 if (kind == 0) {
2769 /* current segment */
2770 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2771 goto error;
2772 }
2773 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2774 goto error;
2775 }
2776 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002777 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002778 goto error;
2779 }
2780 } else if (kind == 1) {
2781 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2782 goto error;
2783 }
2784 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2785 goto error;
2786 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002787 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002788 goto error;
2789 }
2790 } else if (kind == 2) {
2791 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2792 goto error;
2793 }
2794 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2795 goto error;
2796 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002797 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002798 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002799 goto error;
2800 }
2801 }
2802
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002803 /* next segment (next OR) */
2804 seg_ptr = strchr(seg_ptr, '|');
2805 if (!seg_ptr) {
2806 break;
2807 }
2808 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002809 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002810 }
2811
2812 /* check local restrictions against superior ones */
2813 if (intv) {
2814 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002815 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002816
2817 while (tmp_local_intv && tmp_intv) {
2818 /* reuse local variables */
2819 if (kind == 0) {
2820 local_umin = tmp_local_intv->value.uval.min;
2821 local_umax = tmp_local_intv->value.uval.max;
2822
2823 /* it must be in this interval */
2824 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2825 /* this interval is covered, next one */
2826 if (local_umax <= tmp_intv->value.uval.max) {
2827 tmp_local_intv = tmp_local_intv->next;
2828 continue;
2829 /* ascending order of restrictions -> fail */
2830 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002831 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002832 }
2833 }
2834 } else if (kind == 1) {
2835 local_smin = tmp_local_intv->value.sval.min;
2836 local_smax = tmp_local_intv->value.sval.max;
2837
2838 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2839 if (local_smax <= tmp_intv->value.sval.max) {
2840 tmp_local_intv = tmp_local_intv->next;
2841 continue;
2842 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002843 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002844 }
2845 }
2846 } else if (kind == 2) {
2847 local_fmin = tmp_local_intv->value.fval.min;
2848 local_fmax = tmp_local_intv->value.fval.max;
2849
Michal Vasko4d1f0482016-09-19 14:35:06 +02002850 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002851 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002852 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002853 tmp_local_intv = tmp_local_intv->next;
2854 continue;
2855 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002856 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002857 }
2858 }
2859 }
2860
2861 tmp_intv = tmp_intv->next;
2862 }
2863
2864 /* some interval left uncovered -> fail */
2865 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002866 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002867 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002868 }
2869
Michal Vaskoaeb51802016-04-11 10:58:47 +02002870 /* append the local intervals to all the intervals of the superior types, return it all */
2871 if (intv) {
2872 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2873 tmp_intv->next = local_intv;
2874 } else {
2875 intv = local_intv;
2876 }
2877 *ret = intv;
2878
2879 return EXIT_SUCCESS;
2880
2881error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002882 while (intv) {
2883 tmp_intv = intv->next;
2884 free(intv);
2885 intv = tmp_intv;
2886 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002887 while (local_intv) {
2888 tmp_local_intv = local_intv->next;
2889 free(local_intv);
2890 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002891 }
2892
Michal Vaskoaeb51802016-04-11 10:58:47 +02002893 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002894}
2895
Michal Vasko730dfdf2015-08-11 14:48:05 +02002896/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002897 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2898 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002899 *
2900 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002901 * @param[in] mod_name Typedef name module name.
2902 * @param[in] module Main module.
2903 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002904 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002905 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002906 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002907 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002908int
Michal Vasko1e62a092015-12-01 12:27:20 +01002909resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2910 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002911{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002912 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002913 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002914 int tpdf_size;
2915
Michal Vasko1dca6882015-10-22 14:29:42 +02002916 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002917 /* no prefix, try built-in types */
2918 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2919 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002920 if (ret) {
2921 *ret = ly_types[i].def;
2922 }
2923 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002924 }
2925 }
2926 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002927 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002928 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002929 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002930 }
2931 }
2932
Michal Vasko1dca6882015-10-22 14:29:42 +02002933 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002934 /* search in local typedefs */
2935 while (parent) {
2936 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002937 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002938 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2939 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002940 break;
2941
Radek Krejci76512572015-08-04 09:47:08 +02002942 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002943 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2944 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002945 break;
2946
Radek Krejci76512572015-08-04 09:47:08 +02002947 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002948 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2949 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002950 break;
2951
Radek Krejci76512572015-08-04 09:47:08 +02002952 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002953 case LYS_ACTION:
2954 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2955 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002956 break;
2957
Radek Krejci76512572015-08-04 09:47:08 +02002958 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002959 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2960 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002961 break;
2962
Radek Krejci76512572015-08-04 09:47:08 +02002963 case LYS_INPUT:
2964 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002965 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2966 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002967 break;
2968
2969 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002970 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002971 continue;
2972 }
2973
2974 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002975 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002976 match = &tpdf[i];
2977 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002978 }
2979 }
2980
Michal Vaskodcf98e62016-05-05 17:53:53 +02002981 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002982 }
Radek Krejcic071c542016-01-27 14:57:51 +01002983 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002984 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002985 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002986 if (!module) {
2987 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002988 }
2989 }
2990
2991 /* search in top level typedefs */
2992 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002993 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002994 match = &module->tpdf[i];
2995 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002996 }
2997 }
2998
2999 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003000 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003001 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003002 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 +02003003 match = &module->inc[i].submodule->tpdf[j];
3004 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003005 }
3006 }
3007 }
3008
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003009 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003010
3011check_leafref:
3012 if (ret) {
3013 *ret = match;
3014 }
3015 if (match->type.base == LY_TYPE_LEAFREF) {
3016 while (!match->type.info.lref.path) {
3017 match = match->type.der;
3018 assert(match);
3019 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003020 }
3021 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003022}
3023
Michal Vasko1dca6882015-10-22 14:29:42 +02003024/**
3025 * @brief Check the default \p value of the \p type. Logs directly.
3026 *
3027 * @param[in] type Type definition to use.
3028 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003029 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003030 *
3031 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3032 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003033static int
Radek Krejci51673202016-11-01 17:00:32 +01003034check_default(struct lys_type *type, const char **value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003035{
Radek Krejcibad2f172016-08-02 11:04:15 +02003036 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003037 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003038 const char *dflt = NULL;
Radek Krejci37b756f2016-01-18 10:15:03 +01003039 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003040
Radek Krejci51673202016-11-01 17:00:32 +01003041 assert(value);
3042
Radek Krejcic13db382016-08-16 10:52:42 +02003043 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003044 /* the type was not resolved yet, nothing to do for now */
3045 return EXIT_FAILURE;
3046 }
3047
Radek Krejci51673202016-11-01 17:00:32 +01003048 dflt = *value;
3049 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003050 /* we do not have a new default value, so is there any to check even, in some base type? */
3051 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3052 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003053 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003054 break;
3055 }
3056 }
3057
Radek Krejci51673202016-11-01 17:00:32 +01003058 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003059 /* no default value, nothing to check, all is well */
3060 return EXIT_SUCCESS;
3061 }
3062
3063 /* 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)? */
3064 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003065 case LY_TYPE_IDENT:
3066 case LY_TYPE_INST:
3067 case LY_TYPE_LEAFREF:
3068 case LY_TYPE_BOOL:
3069 case LY_TYPE_EMPTY:
3070 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3071 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003072 case LY_TYPE_BITS:
3073 /* the default value must match the restricted list of values, if the type was restricted */
3074 if (type->info.bits.count) {
3075 break;
3076 }
3077 return EXIT_SUCCESS;
3078 case LY_TYPE_ENUM:
3079 /* the default value must match the restricted list of values, if the type was restricted */
3080 if (type->info.enums.count) {
3081 break;
3082 }
3083 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003084 case LY_TYPE_DEC64:
3085 if (type->info.dec64.range) {
3086 break;
3087 }
3088 return EXIT_SUCCESS;
3089 case LY_TYPE_BINARY:
3090 if (type->info.binary.length) {
3091 break;
3092 }
3093 return EXIT_SUCCESS;
3094 case LY_TYPE_INT8:
3095 case LY_TYPE_INT16:
3096 case LY_TYPE_INT32:
3097 case LY_TYPE_INT64:
3098 case LY_TYPE_UINT8:
3099 case LY_TYPE_UINT16:
3100 case LY_TYPE_UINT32:
3101 case LY_TYPE_UINT64:
3102 if (type->info.num.range) {
3103 break;
3104 }
3105 return EXIT_SUCCESS;
3106 case LY_TYPE_STRING:
3107 if (type->info.str.length || type->info.str.patterns) {
3108 break;
3109 }
3110 return EXIT_SUCCESS;
3111 case LY_TYPE_UNION:
3112 /* way too much trouble learning whether we need to check the default again, so just do it */
3113 break;
3114 default:
3115 LOGINT;
3116 return -1;
3117 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003118 } else if (type->base == LY_TYPE_EMPTY) {
3119 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3120 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3121 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003122 }
3123
Michal Vasko1dca6882015-10-22 14:29:42 +02003124 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003125 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003126 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003127 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003128 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003129 if (!node.schema) {
3130 LOGMEM;
3131 return -1;
3132 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003133 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003134 if (!node.schema->name) {
3135 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003136 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003137 return -1;
3138 }
Michal Vasko56826402016-03-02 11:11:37 +01003139 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003140 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003141
Radek Krejci37b756f2016-01-18 10:15:03 +01003142 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003143 if (!type->info.lref.target) {
3144 ret = EXIT_FAILURE;
3145 goto finish;
3146 }
Radek Krejci51673202016-11-01 17:00:32 +01003147 ret = check_default(&type->info.lref.target->type, &dflt, module);
3148 if (!ret) {
3149 /* adopt possibly changed default value to its canonical form */
3150 if (*value) {
3151 *value = dflt;
3152 }
3153 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003154 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003155 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003156 /* possible forward reference */
3157 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003158 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003159 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003160 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3161 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3162 /* we have refined bits/enums */
3163 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3164 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003165 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003166 }
3167 }
Radek Krejci51673202016-11-01 17:00:32 +01003168 } else {
3169 /* success - adopt canonical form from the node into the default value */
3170 if (dflt != node.value_str) {
3171 /* this can happen only if we have non-inherited default value,
3172 * inherited default values are already in canonical form */
3173 assert(dflt == *value);
3174 *value = node.value_str;
3175 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003176 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003177 }
3178
3179finish:
3180 if (node.value_type == LY_TYPE_BITS) {
3181 free(node.value.bit);
3182 }
3183 free((char *)node.schema->name);
3184 free(node.schema);
3185
3186 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187}
3188
Michal Vasko730dfdf2015-08-11 14:48:05 +02003189/**
3190 * @brief Check a key for mandatory attributes. Logs directly.
3191 *
3192 * @param[in] key The key to check.
3193 * @param[in] flags What flags to check.
3194 * @param[in] list The list of all the keys.
3195 * @param[in] index Index of the key in the key list.
3196 * @param[in] name The name of the keys.
3197 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003198 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003199 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003200 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003201static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003202check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003203{
Radek Krejciadb57612016-02-16 13:34:34 +01003204 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205 char *dup = NULL;
3206 int j;
3207
3208 /* existence */
3209 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003210 if (name[len] != '\0') {
3211 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003212 if (!dup) {
3213 LOGMEM;
3214 return -1;
3215 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003216 dup[len] = '\0';
3217 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003218 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003219 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003220 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003221 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003222 }
3223
3224 /* uniqueness */
3225 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003226 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003227 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003228 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003229 }
3230 }
3231
3232 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003233 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003234 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003235 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003236 }
3237
3238 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003239 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003240 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003241 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003242 }
3243
3244 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003245 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003246 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003247 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003248 }
3249
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003250 /* key is not placed from augment */
3251 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003252 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003253 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003254 return -1;
3255 }
3256
Radek Krejci3f21ada2016-08-01 13:34:31 +02003257 /* key is not when/if-feature -conditional */
3258 j = 0;
3259 if (key->when || (key->iffeature_size && (j = 1))) {
3260 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003261 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003262 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003263 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003264 }
3265
Michal Vasko0b85aa82016-03-07 14:37:43 +01003266 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003267}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003268
3269/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003270 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003271 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003272 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003273 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003274 *
3275 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3276 */
3277int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003278resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003279{
Radek Krejci581ce772015-11-10 17:22:40 +01003280 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003281 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003282
Radek Krejcif3c71de2016-04-11 12:45:46 +02003283 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003284 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003285 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003286 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003287 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003288 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003289 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003290 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003291 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003292 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003293 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003294 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003295 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003296 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003297 }
Radek Krejci581ce772015-11-10 17:22:40 +01003298 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003299 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003300 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003301 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003302 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003303 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003304 }
3305
Radek Krejcicf509982015-12-15 09:22:44 +01003306 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003307 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003308 return -1;
3309 }
3310
Radek Krejcid09d1a52016-08-11 14:05:45 +02003311 /* check that all unique's targets are of the same config type */
3312 if (*trg_type) {
3313 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3314 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003315 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003316 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3317 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3318 return -1;
3319 }
3320 } else {
3321 /* first unique */
3322 if (leaf->flags & LYS_CONFIG_W) {
3323 *trg_type = 1;
3324 } else {
3325 *trg_type = 2;
3326 }
3327 }
3328
Radek Krejcica7efb72016-01-18 13:06:01 +01003329 /* set leaf's unique flag */
3330 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3331
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003332 return EXIT_SUCCESS;
3333
3334error:
3335
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003336 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003337}
3338
Radek Krejci0c0086a2016-03-24 15:20:28 +01003339void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003340unres_data_del(struct unres_data *unres, uint32_t i)
3341{
3342 /* there are items after the one deleted */
3343 if (i+1 < unres->count) {
3344 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003345 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003346
3347 /* deleting the last item */
3348 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003349 free(unres->node);
3350 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003351 }
3352
3353 /* if there are no items after and it is not the last one, just move the counter */
3354 --unres->count;
3355}
3356
Michal Vasko0491ab32015-08-19 14:28:29 +02003357/**
3358 * @brief Resolve (find) a data node from a specific module. Does not log.
3359 *
3360 * @param[in] mod Module to search in.
3361 * @param[in] name Name of the data node.
3362 * @param[in] nam_len Length of the name.
3363 * @param[in] start Data node to start the search from.
3364 * @param[in,out] parents Resolved nodes. If there are some parents,
3365 * they are replaced (!!) with the resolvents.
3366 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003367 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003368 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003369static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003370resolve_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 +02003371{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003373 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003374 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003375
Michal Vasko23b61ec2015-08-19 11:19:50 +02003376 if (!parents->count) {
3377 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003378 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003379 if (!parents->node) {
3380 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003381 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003382 }
Michal Vaskocf024702015-10-08 15:01:42 +02003383 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003385 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003386 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003388 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 continue;
3390 }
3391 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003392 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003393 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3394 && node->schema->name[nam_len] == '\0') {
3395 /* matching target */
3396 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003397 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003398 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 flag = 1;
3400 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003401 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003402 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003403 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3404 if (!parents->node) {
3405 return EXIT_FAILURE;
3406 }
Michal Vaskocf024702015-10-08 15:01:42 +02003407 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003408 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 }
3410 }
3411 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003412
3413 if (!flag) {
3414 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003415 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003416 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003417 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003418 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003419 }
3420
Michal Vasko0491ab32015-08-19 14:28:29 +02003421 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003422}
3423
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003424/**
3425 * @brief Resolve (find) a data node. Does not log.
3426 *
Radek Krejci581ce772015-11-10 17:22:40 +01003427 * @param[in] mod_name Module name of the data node.
3428 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003429 * @param[in] name Name of the data node.
3430 * @param[in] nam_len Length of the name.
3431 * @param[in] start Data node to start the search from.
3432 * @param[in,out] parents Resolved nodes. If there are some parents,
3433 * they are replaced (!!) with the resolvents.
3434 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003435 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003436 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003437static int
Radek Krejci581ce772015-11-10 17:22:40 +01003438resolve_data_node(const char *mod_name, int mod_name_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003439 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003440{
Michal Vasko1e62a092015-12-01 12:27:20 +01003441 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003442 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003443
Michal Vasko23b61ec2015-08-19 11:19:50 +02003444 assert(start);
3445
Michal Vasko31fc3672015-10-21 12:08:13 +02003446 if (mod_name) {
3447 /* we have mod_name, find appropriate module */
3448 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003449 if (!str) {
3450 LOGMEM;
3451 return -1;
3452 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003453 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3454 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003455 if (!mod) {
3456 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003457 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003458 }
3459 } else {
3460 /* no prefix, module is the same as of current node */
3461 mod = start->schema->module;
3462 }
3463
3464 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003465}
3466
Michal Vasko730dfdf2015-08-11 14:48:05 +02003467/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003468 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003469 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003470 *
Michal Vaskobb211122015-08-19 14:03:11 +02003471 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003472 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003473 * @param[in,out] node_match Nodes satisfying the restriction
3474 * without the predicate. Nodes not
3475 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003476 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003477 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003478 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003479 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003481resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003482 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003483{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003484 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003485 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003486 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003487 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3488 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003489 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003490 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003491
3492 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003493 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003494 if (!source_match.node) {
3495 LOGMEM;
3496 return -1;
3497 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003498 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003499 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003500 if (!dest_match.node) {
3501 LOGMEM;
3502 return -1;
3503 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003504
3505 do {
3506 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3507 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003508 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003509 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003510 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003512 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003513 pred += i;
3514
Michal Vasko23b61ec2015-08-19 11:19:50 +02003515 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003516 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003517 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003518
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003520 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003521 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003522 i = 0;
3523 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003524 }
3525
3526 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003527 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003528 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003529 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3530 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003531 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003532 rc = -1;
3533 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003534 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003535 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003536 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003537 dest_match.node[0] = dest_match.node[0]->parent;
3538 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003539 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003540 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003541 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003542 }
3543 }
3544 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003545 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003546 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003547 i = 0;
3548 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549 }
3550
3551 if (pke_len == pke_parsed) {
3552 break;
3553 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003554 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003556 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003557 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003558 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003559 }
3560 pke_parsed += i;
3561 }
3562
3563 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003564 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3565 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3566 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3567 }
3568 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3569 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3570 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3571 }
3572 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573 goto remove_leafref;
3574 }
3575
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003576 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003577 goto remove_leafref;
3578 }
3579
3580 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003581 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003582 continue;
3583
3584remove_leafref:
3585 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003586 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003587 }
3588 } while (has_predicate);
3589
Michal Vaskocf024702015-10-08 15:01:42 +02003590 free(source_match.node);
3591 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003592 if (parsed) {
3593 *parsed = parsed_loc;
3594 }
3595 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003596
3597error:
3598
3599 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003600 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003601 }
3602 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003603 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003604 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003605 if (parsed) {
3606 *parsed = -parsed_loc+i;
3607 }
3608 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003609}
3610
Michal Vasko730dfdf2015-08-11 14:48:05 +02003611/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003612 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003613 *
Michal Vaskocf024702015-10-08 15:01:42 +02003614 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003615 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003616 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003617 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003618 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003619 */
Michal Vasko184521f2015-09-24 13:14:26 +02003620static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003621resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003622{
Radek Krejci71b795b2015-08-10 16:20:39 +02003623 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003624 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003625 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003626 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003627
Michal Vaskocf024702015-10-08 15:01:42 +02003628 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003629
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003630 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003631 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003632
3633 /* searching for nodeset */
3634 do {
Radek Krejcif7ed4c32016-10-27 16:20:03 +02003635 if ((i = parse_path_arg(node->schema->module, path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003636 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003637 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003638 goto error;
3639 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003640 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003641 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003642
Michal Vasko23b61ec2015-08-19 11:19:50 +02003643 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003644 if (parent_times > 0) {
3645 data = node;
3646 for (i = 1; i < parent_times; ++i) {
3647 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003648 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003649 } else if (!parent_times) {
3650 data = node->child;
3651 } else {
3652 /* absolute path */
3653 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003654 }
3655
Michal Vaskobfd98e62016-09-02 09:50:05 +02003656 /* we may still be parsing it and the pointer is not correct yet */
3657 if (data->prev) {
3658 while (data->prev->next) {
3659 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003660 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003661 }
3662 }
3663
3664 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003665 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003666 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003667 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003668 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003669 goto error;
3670 }
3671
3672 if (has_predicate) {
3673 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003674 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003675 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3676 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003677 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003678 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003679 continue;
3680 }
3681
3682 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003683 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003684 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003685 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003686 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003687 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003688 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003689 goto error;
3690 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003691 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003692 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003693
Michal Vasko23b61ec2015-08-19 11:19:50 +02003694 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003695 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003696 goto error;
3697 }
3698 }
3699 } while (path[0] != '\0');
3700
Michal Vaskof02e3742015-08-05 16:27:02 +02003701 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003702
3703error:
3704
Michal Vaskocf024702015-10-08 15:01:42 +02003705 free(ret->node);
3706 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003707 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003708
Michal Vasko0491ab32015-08-19 14:28:29 +02003709 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003710}
3711
Michal Vaskoe27516a2016-10-10 17:55:31 +00003712static int
3713resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3714{
3715 int dep1, dep2;
3716 const struct lys_node *node;
3717
3718 if (lys_parent(op_node)) {
3719 /* inner operation (notif/action) */
3720 if (abs_path) {
3721 return 1;
3722 } else {
3723 /* compare depth of both nodes */
3724 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3725 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3726 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3727 return 1;
3728 }
3729 }
3730 } else {
3731 /* top-level operation (notif/rpc) */
3732 if (op_node != first_node) {
3733 return 1;
3734 }
3735 }
3736
3737 return 0;
3738}
3739
Michal Vasko730dfdf2015-08-11 14:48:05 +02003740/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003741 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003742 *
Michal Vaskobb211122015-08-19 14:03:11 +02003743 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003744 * @param[in] context_node Predicate context node (where the predicate is placed).
3745 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003746 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003747 *
Michal Vasko184521f2015-09-24 13:14:26 +02003748 * @return 0 on forward reference, otherwise the number
3749 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003750 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003751 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003752static int
Radek Krejciadb57612016-02-16 13:34:34 +01003753resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003754 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003755{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003756 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003757 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003758 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003759 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3760 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003761
3762 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003763 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003764 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003765 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003766 return -parsed+i;
3767 }
3768 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003769 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003770
Michal Vasko58090902015-08-13 14:04:15 +02003771 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003772 if (sour_pref) {
3773 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3774 } else {
3775 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003776 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003777 rc = lys_get_data_sibling(trg_mod, context_node->child, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003778 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003779 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003780 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003781 }
3782
3783 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003784 dest_parent_times = 0;
3785 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003786 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3787 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003788 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path_key_expr[-i], path_key_expr-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 return -parsed;
3790 }
3791 pke_parsed += i;
3792
Radek Krejciadb57612016-02-16 13:34:34 +01003793 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003794 /* path is supposed to be evaluated in data tree, so we have to skip
3795 * all schema nodes that cannot be instantiated in data tree */
3796 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003797 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003798 dst_node = lys_parent(dst_node));
3799
Michal Vasko1f76a282015-08-04 16:16:53 +02003800 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003801 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003802 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003803 }
3804 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003805 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003806 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003807 if (dest_pref) {
3808 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3809 } else {
3810 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003811 }
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003812 rc = lys_get_data_sibling(trg_mod, dst_node->child, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003814 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003815 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003816 }
3817
Michal Vaskoe27516a2016-10-10 17:55:31 +00003818 if (first_iter) {
3819 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003820 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003821 }
3822 first_iter = 0;
3823 }
3824
Michal Vasko1f76a282015-08-04 16:16:53 +02003825 if (pke_len == pke_parsed) {
3826 break;
3827 }
3828
3829 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3830 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003831 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003832 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003833 return -parsed;
3834 }
3835 pke_parsed += i;
3836 }
3837
3838 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003839 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003840 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003841 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003842 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003843 return -parsed;
3844 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003845 } while (has_predicate);
3846
3847 return parsed;
3848}
3849
Michal Vasko730dfdf2015-08-11 14:48:05 +02003850/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003851 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003852 *
Michal Vaskobb211122015-08-19 14:03:11 +02003853 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003854 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003855 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3856 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003857 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003858 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003859 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003860 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003861static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003862resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003863 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003864{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003865 const struct lys_node *node, *op_node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003866 const struct lys_module *mod;
3867 struct lys_module *mod_start;
Michal Vasko1f76a282015-08-04 16:16:53 +02003868 const char *id, *prefix, *name;
3869 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003870 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003871
Michal Vasko184521f2015-09-24 13:14:26 +02003872 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003873 parent_times = 0;
3874 id = path;
3875
Michal Vaskoe27516a2016-10-10 17:55:31 +00003876 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003877 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003878 for (op_node = lys_parent(parent);
3879 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3880 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003881 }
3882
Radek Krejci990af1f2016-11-09 13:53:36 +01003883 mod_start = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003884 do {
Radek Krejci990af1f2016-11-09 13:53:36 +01003885 if ((i = parse_path_arg(mod_start, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003886 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003887 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003888 }
3889 id += i;
3890
Michal Vasko184521f2015-09-24 13:14:26 +02003891 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003892 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003893 /* resolve prefix of the module */
Radek Krejci990af1f2016-11-09 13:53:36 +01003894 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3895 if (!mod) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003896 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3897 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003898 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003899 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003900 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003901 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003902 if (!mod->implemented) {
3903 /* make the found module implemented */
3904 if (lys_set_implemented(mod)) {
3905 return EXIT_FAILURE;
3906 }
3907 }
3908 }
3909 /* get start node */
3910 if (!mod->data) {
3911 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3912 "leafref", path);
3913 return EXIT_FAILURE;
3914 }
3915 node = mod->data;
3916
Michal Vasko1f76a282015-08-04 16:16:53 +02003917 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003918 if (parent_tpdf) {
3919 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003920 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003921 return -1;
3922 }
3923
Michal Vasko94458082016-10-07 14:34:36 +02003924 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3925 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003926 /* path is supposed to be evaluated in data tree, so we have to skip
3927 * all schema nodes that cannot be instantiated in data tree */
3928 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003929 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003930 node = lys_parent(node));
3931
Michal Vasko1f76a282015-08-04 16:16:53 +02003932 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003933 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003934 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003935 }
3936 }
Radek Krejci990af1f2016-11-09 13:53:36 +01003937
3938 /* now we have to check that if we are going into a node from a different module,
3939 * the module is implemented (so its augments are applied) */
3940 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3941 if (!mod) {
3942 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3943 return EXIT_FAILURE;
3944 }
3945 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003946 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003947 if (!mod->implemented) {
3948 /* make the found module implemented */
3949 if (lys_set_implemented(mod)) {
3950 return EXIT_FAILURE;
3951 }
3952 }
3953 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003954 } else {
3955 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003956 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003957 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003958 } else {
Radek Krejci990af1f2016-11-09 13:53:36 +01003959 /* we have to first check that the module we are going into is implemented */
3960 mod = prefix ? lys_get_import_module(mod_start, NULL, 0, prefix, pref_len) : mod_start;
3961 if (!mod) {
3962 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3963 return EXIT_FAILURE;
3964 }
3965 if (!mod->implemented) {
Radek Krejci2eee5c02016-12-06 19:18:05 +01003966 mod = lys_implemented_module(mod);
Radek Krejci990af1f2016-11-09 13:53:36 +01003967 if (!mod->implemented) {
3968 /* make the found module implemented */
3969 if (lys_set_implemented(mod)) {
3970 return EXIT_FAILURE;
3971 }
3972 }
3973 }
3974
Michal Vasko7dc71d02016-03-15 10:42:28 +01003975 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003976 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003977 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003978 return -1;
3979 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003980 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003981 if (!node) {
3982 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3983 "leafref", path);
3984 return EXIT_FAILURE;
3985 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003986 }
3987
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003988 rc = lys_get_data_sibling(mod, node, name, nam_len, LYS_LIST | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF
3989 | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003990 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003991 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003992 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003993 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003994
Michal Vaskoe27516a2016-10-10 17:55:31 +00003995 if (first_iter) {
3996 /* set external dependency flag, we can decide based on the first found node */
3997 if (!parent_tpdf && op_node && parent_times &&
3998 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003999 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00004000 }
4001 first_iter = 0;
4002 }
4003
Michal Vasko1f76a282015-08-04 16:16:53 +02004004 if (has_predicate) {
4005 /* we have predicate, so the current result must be list */
4006 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004007 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004008 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02004009 }
4010
Michal Vaskoe27516a2016-10-10 17:55:31 +00004011 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004012 if (i <= 0) {
4013 if (i == 0) {
4014 return EXIT_FAILURE;
4015 } else { /* i < 0 */
4016 return -1;
4017 }
Michal Vasko1f76a282015-08-04 16:16:53 +02004018 }
4019 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02004020 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02004021 }
4022 } while (id[0]);
4023
Michal Vaskoca917682016-07-25 11:00:37 +02004024 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01004025 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02004026 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01004027 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Leafref target \"%s\" is not a leaf nor a leaf-list.", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004028 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02004029 }
4030
Radek Krejcicf509982015-12-15 09:22:44 +01004031 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01004032 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01004033 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01004034 return -1;
4035 }
4036
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004037 if (ret) {
4038 *ret = node;
4039 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004040
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004041 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02004042}
4043
Michal Vasko730dfdf2015-08-11 14:48:05 +02004044/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004045 * @brief Resolve instance-identifier predicate in JSON data format.
4046 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004047 *
Michal Vaskobb211122015-08-19 14:03:11 +02004048 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004049 * @param[in,out] node_match Nodes matching the restriction without
4050 * the predicate. Nodes not satisfying
4051 * the predicate are removed.
4052 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004053 * @return Number of characters successfully parsed,
4054 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004055 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004056static int
Michal Vaskof39142b2015-10-21 11:40:05 +02004057resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058{
Michal Vasko730dfdf2015-08-11 14:48:05 +02004059 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02004060 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004061 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004062 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004063 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004064
Michal Vasko1f2cc332015-08-19 11:18:32 +02004065 assert(pred && node_match->count);
4066
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004067 idx = -1;
4068 parsed = 0;
4069
Michal Vaskob2f40be2016-09-08 16:03:48 +02004070 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004071 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02004072 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004073 return -parsed+i;
4074 }
4075 parsed += i;
4076 pred += i;
4077
4078 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004079 /* pos */
4080 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004081 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004082 } else if (name[0] != '.') {
4083 /* list keys */
4084 if (pred_iter < 0) {
4085 pred_iter = 1;
4086 } else {
4087 ++pred_iter;
4088 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004089 }
4090
Michal Vaskof2f28a12016-09-09 12:43:06 +02004091 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004092 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004093 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004094 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02004095 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004096 goto remove_instid;
4097 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004098
4099 target = node_match->node[j];
4100 /* check the value */
4101 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4102 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4103 goto remove_instid;
4104 }
4105
4106 } else if (!value) {
4107 /* keyless list position */
4108 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
4109 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
4110 goto remove_instid;
4111 }
4112
4113 if (idx != cur_idx) {
4114 goto remove_instid;
4115 }
4116
4117 } else {
4118 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02004119 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004120 goto remove_instid;
4121 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004122
4123 /* key module must match the list module */
4124 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
4125 || node_match->node[j]->schema->module->name[mod_len]) {
4126 goto remove_instid;
4127 }
4128 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02004129 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02004130 if (!target) {
4131 goto remove_instid;
4132 }
4133 if ((struct lys_node_leaf *)target->schema !=
4134 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
4135 goto remove_instid;
4136 }
4137
4138 /* check the value */
4139 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4140 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4141 goto remove_instid;
4142 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004143 }
4144
Michal Vaskob2f40be2016-09-08 16:03:48 +02004145 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004146 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004147 continue;
4148
4149remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004150 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004151 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004152 }
4153 } while (has_predicate);
4154
Michal Vaskob2f40be2016-09-08 16:03:48 +02004155 /* check that all list keys were specified */
4156 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004157 j = 0;
4158 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004159 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4160 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4161 /* not enough predicates, just remove the list instance */
4162 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004163 } else {
4164 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004165 }
4166 }
4167
4168 if (!node_match->count) {
4169 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4170 }
4171 }
4172
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004173 return parsed;
4174}
4175
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004176int
Michal Vasko769f8032017-01-24 13:11:55 +01004177lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004178{
4179 struct lys_node *parent, *elem;
4180 struct lyxp_set set;
4181 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004182 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004183
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004184 if (check_place) {
4185 parent = node;
4186 while (parent) {
4187 if (parent->nodetype == LYS_GROUPING) {
4188 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004189 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004190 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004191 if (parent->nodetype == LYS_AUGMENT) {
4192 if (!((struct lys_node_augment *)parent)->target) {
Radek Krejcidf46e222016-11-08 11:57:37 +01004193 /* unresolved augment */
4194 if (parent->module->implemented) {
4195 /* skip for now (will be checked later) */
4196 return EXIT_FAILURE;
4197 } else {
4198 /* not implemented augment, skip resolving */
4199 return EXIT_SUCCESS;
4200 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004201 } else {
4202 parent = ((struct lys_node_augment *)parent)->target;
4203 continue;
4204 }
4205 }
4206 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004207 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004208 }
4209
Michal Vasko769f8032017-01-24 13:11:55 +01004210 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4211 if (ret == -1) {
4212 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004213 }
4214
4215 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4216
4217 for (i = 0; i < set.used; ++i) {
4218 /* skip roots'n'stuff */
4219 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4220 /* XPath expression cannot reference "lower" status than the node that has the definition */
4221 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4222 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4223 return -1;
4224 }
4225
4226 if (parent) {
4227 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4228 if (!elem) {
4229 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004230 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004231 break;
4232 }
4233 }
4234 }
4235 }
4236
4237 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004238 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004239}
4240
Radek Krejcif71f48f2016-10-25 16:37:24 +02004241static int
4242check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4243{
4244 int i;
4245
4246 if (type->base == LY_TYPE_LEAFREF) {
4247 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && (type->info.lref.target->flags & LYS_CONFIG_R)) {
4248 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The %s is config but refers to a non-config %s.",
4249 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4250 return -1;
4251 }
4252 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4253 * of leafref resolving (lys_leaf_add_leafref_target()) */
4254 } else if (type->base == LY_TYPE_UNION) {
4255 for (i = 0; i < type->info.uni.count; i++) {
4256 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4257 return -1;
4258 }
4259 }
4260 }
4261 return 0;
4262}
4263
Michal Vasko9e635ac2016-10-17 11:44:09 +02004264/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004265 * @brief Passes config flag down to children, skips nodes without config flags.
4266 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004267 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004268 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004269 * @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 +02004270 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004271 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004272 *
4273 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004274 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004275static int
Radek Krejcib3142312016-11-09 11:04:12 +01004276inherit_config_flag(struct lys_node *node, int flags, int clear, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004277{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004278 struct lys_node_leaf *leaf;
4279
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004280 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004281 LY_TREE_FOR(node, node) {
Radek Krejcib3142312016-11-09 11:04:12 +01004282 if (lys_has_xpath(node) && unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004283 return -1;
4284 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004285 if (clear) {
4286 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004287 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004288 } else {
4289 if (node->flags & LYS_CONFIG_SET) {
4290 /* skip nodes with an explicit config value */
4291 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4292 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004293 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004294 return -1;
4295 }
4296 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004297 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004298
4299 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4300 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4301 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004302 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4303 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004304 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4305 return -1;
4306 }
4307 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004308 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004309 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Radek Krejcib3142312016-11-09 11:04:12 +01004310 if (inherit_config_flag(node->child, flags, clear, unres)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004311 return -1;
4312 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004313 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4314 leaf = (struct lys_node_leaf *)node;
4315 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004316 return -1;
4317 }
4318 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004319 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004320
4321 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004322}
4323
Michal Vasko730dfdf2015-08-11 14:48:05 +02004324/**
Michal Vasko7178e692016-02-12 15:58:05 +01004325 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004326 *
Michal Vaskobb211122015-08-19 14:03:11 +02004327 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004328 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Radek Krejcib3142312016-11-09 11:04:12 +01004329 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004330 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004331 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004332 */
Michal Vasko7178e692016-02-12 15:58:05 +01004333static int
Radek Krejcib3142312016-11-09 11:04:12 +01004334resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004335{
Michal Vaskoe022a562016-09-27 14:24:15 +02004336 int rc, clear_config;
Radek Krejci80056d52017-01-05 13:13:33 +01004337 unsigned int u;
Michal Vasko1d87a922015-08-21 12:57:16 +02004338 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004339 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004340 struct lys_module *mod;
Radek Krejci80056d52017-01-05 13:13:33 +01004341 struct lys_ext_instance *ext;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004342
Michal Vasko15b36692016-08-26 15:29:54 +02004343 assert(aug && !aug->target);
Radek Krejcidf46e222016-11-08 11:57:37 +01004344 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004345
Michal Vasko15b36692016-08-26 15:29:54 +02004346 /* resolve target node */
Radek Krejcidf46e222016-11-08 11:57:37 +01004347 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), mod->implemented, &aug_target);
Michal Vasko15b36692016-08-26 15:29:54 +02004348 if (rc == -1) {
4349 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004350 } else if (rc > 0) {
Michal Vasko15b36692016-08-26 15:29:54 +02004351 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4352 return -1;
Radek Krejci5fb4c382016-11-28 09:21:42 +01004353 } else if (rc == 0 && aug->target) {
4354 /* augment was resolved as a side effect of setting module implemented when
4355 * resolving augment schema nodeid, so we are done here */
4356 return 0;
Michal Vasko15b36692016-08-26 15:29:54 +02004357 }
Radek Krejcidf46e222016-11-08 11:57:37 +01004358 if (!aug_target && mod->implemented) {
Michal Vasko15b36692016-08-26 15:29:54 +02004359 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4360 return EXIT_FAILURE;
4361 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004362 /* check that we want to connect augment into its target */
Radek Krejci27fe55e2016-09-13 17:13:35 +02004363 if (!mod->implemented) {
4364 /* it must be augment only to the same module,
4365 * otherwise we do not apply augment in not-implemented
4366 * module. If the module is set to be implemented in future,
4367 * the augment is being resolved and checked again */
Radek Krejcidf46e222016-11-08 11:57:37 +01004368 if (!aug_target) {
4369 /* target was not even resolved */
4370 return EXIT_SUCCESS;
4371 }
4372 /* target was resolved, but it may refer another module */
4373 for (sub = (struct lys_node *)aug_target; sub; sub = lys_parent(sub)) {
Radek Krejci27fe55e2016-09-13 17:13:35 +02004374 if (lys_node_module(sub) != mod) {
4375 /* this is not an implemented module and the augment
4376 * target some other module, so avoid its connecting
4377 * to the target */
4378 return EXIT_SUCCESS;
4379 }
4380 }
4381 }
4382
Michal Vasko15b36692016-08-26 15:29:54 +02004383 if (!aug->child) {
4384 /* nothing to do */
4385 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004386 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004387 }
4388
Michal Vaskod58d5962016-03-02 14:29:41 +01004389 /* check for mandatory nodes - if the target node is in another module
4390 * the added nodes cannot be mandatory
4391 */
Michal Vasko15b36692016-08-26 15:29:54 +02004392 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcidf24cbe2016-11-08 11:55:51 +01004393 && (rc = lyp_check_mandatory_augment(aug, aug_target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004394 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004395 }
4396
Michal Vasko07e89ef2016-03-03 13:28:57 +01004397 /* check augment target type and then augment nodes type */
Michal Vaskodb017262017-01-24 13:10:04 +01004398 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
4399 LY_TREE_FOR(aug->child, sub) {
4400 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4401 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4402 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4403 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
4404 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
4405 return -1;
4406 }
4407 }
4408 } else if (aug_target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004409 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004410 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004411 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004412 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004413 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004414 return -1;
4415 }
4416 }
Michal Vasko15b36692016-08-26 15:29:54 +02004417 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004418 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004419 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004420 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004421 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004422 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004423 return -1;
4424 }
4425 }
4426 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004427 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko51e5c582017-01-19 14:16:39 +01004428 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004429 return -1;
4430 }
4431
Radek Krejcic071c542016-01-27 14:57:51 +01004432 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004433 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004434 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004435 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004436 }
4437 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004438
Michal Vasko15b36692016-08-26 15:29:54 +02004439 /* finally reconnect augmenting data into the target - add them to the target child list,
4440 * by setting aug->target we know the augment is fully resolved now */
4441 aug->target = (struct lys_node *)aug_target;
4442 if (aug->target->child) {
4443 sub = aug->target->child->prev; /* remember current target's last node */
4444 sub->next = aug->child; /* connect augmenting data after target's last node */
4445 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4446 aug->child->prev = sub; /* finish connecting of both child lists */
4447 } else {
4448 aug->target->child = aug->child;
4449 }
4450
Michal Vasko9e635ac2016-10-17 11:44:09 +02004451 /* inherit config information from actual parent */
4452 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4453 clear_config = (parent) ? 1 : 0;
4454 LY_TREE_FOR(aug->child, sub) {
Radek Krejcib3142312016-11-09 11:04:12 +01004455 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, unres)) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004456 return -1;
4457 }
4458 }
4459
Radek Krejci80056d52017-01-05 13:13:33 +01004460 /* inherit extensions if any */
4461 for (u = 0; u < aug->target->ext_size; u++) {
4462 ext = aug->target->ext[u]; /* shortcut */
4463 if (ext && ext->def->plugin && (ext->def->plugin->flags & LYEXT_OPT_INHERIT)) {
4464 unres_schema_add_node(mod, unres, &ext, UNRES_EXT_FINALIZE, NULL);
4465 }
4466 }
4467
Radek Krejci27fe55e2016-09-13 17:13:35 +02004468success:
4469 if (mod->implemented) {
4470 /* make target modules also implemented */
4471 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4472 if (lys_set_implemented(sub->module)) {
4473 return -1;
4474 }
4475 }
4476 }
4477
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004478 return EXIT_SUCCESS;
4479}
4480
Radek Krejcie534c132016-11-23 13:32:31 +01004481static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004482resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004483{
4484 enum LY_VLOG_ELEM vlog_type;
4485 void *vlog_node;
4486 unsigned int i, j;
4487 int c_ext = -1, rc;
4488 struct lys_ext *e;
4489 const char *value;
4490 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004491 const struct lys_module *mod;
Radek Krejcie534c132016-11-23 13:32:31 +01004492
4493 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004494 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004495 vlog_node = info->parent;
4496 vlog_type = LY_VLOG_LYS;
4497 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004498 case LYEXT_PAR_MODULE:
4499 case LYEXT_PAR_IMPORT:
4500 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004501 vlog_node = NULL;
4502 vlog_type = LY_VLOG_LYS;
4503 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004504 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004505 vlog_node = NULL;
4506 vlog_node = LY_VLOG_NONE;
4507 break;
4508 }
4509
4510 if (info->datatype == LYS_IN_YIN) {
4511 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004512 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004513 if (!mod) {
4514 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004515 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004516 }
4517
4518 /* find the extension definition */
4519 e = NULL;
4520 for (i = 0; i < mod->extensions_size; i++) {
4521 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4522 e = &mod->extensions[i];
4523 break;
4524 }
4525 }
4526 /* try submodules */
4527 for (j = 0; !e && j < mod->inc_size; j++) {
4528 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4529 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4530 e = &mod->inc[j].submodule->extensions[i];
4531 break;
4532 }
4533 }
4534 }
4535 if (!e) {
4536 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4537 return EXIT_FAILURE;
4538 }
4539
4540 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004541
Radek Krejci72b35992017-01-04 16:27:44 +01004542 if (e->plugin && e->plugin->check_position) {
4543 /* common part - we have plugin with position checking function, use it first */
4544 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4545 /* extension is not allowed here */
4546 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4547 return -1;
4548 }
4549 }
4550
4551 /* common part, even if there is no plugin */
4552 if (e->flags & LYS_YINELEM) {
4553 value = NULL;
4554 c_ext = 0;
4555 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4556 if (!yin->ns) {
4557 /* garbage */
4558 lyxml_free(mod->ctx, yin);
4559 continue;
4560 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4561 /* standard YANG statements are not expected here */
4562 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4563 return -1;
4564 } else if (yin->ns == info->data.yin->ns && ly_strequal(yin->name, e->argument, 1)) {
4565 /* we have the extension's argument */
4566 if (value) {
4567 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004568 return -1;
4569 }
Radek Krejci72b35992017-01-04 16:27:44 +01004570 value = yin->content;
4571 yin->content = NULL;
4572 lyxml_free(mod->ctx, yin);
4573 } else {
4574 /* possible extension instance, processed later */
4575 c_ext++;
4576 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004577 }
4578 }
Radek Krejci72b35992017-01-04 16:27:44 +01004579 if (!value) {
4580 LOGVAL(LYE_MISSCHILDSTMT, vlog_type, vlog_node, e->argument, info->data.yin->name);
4581 return -1;
4582 }
4583 } else if (e->argument) {
4584 value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4585 if (!value) {
4586 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4587 return -1;
4588 }
4589 value = lydict_insert(mod->ctx, value, 0);
4590 } else {
4591 value = NULL;
4592 }
4593 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4594 ((struct lys_ext_instance *)(*ext))->def = e;
4595 ((struct lys_ext_instance *)(*ext))->arg_value = value;
4596 ((struct lys_ext_instance *)(*ext))->parent = info->parent;
4597 ((struct lys_ext_instance *)(*ext))->parent_type = info->parent_type;
4598 ((struct lys_ext_instance *)(*ext))->substmt = info->substmt;
4599 ((struct lys_ext_instance *)(*ext))->substmt_index = info->substmt_index;
4600
4601 /* extension instances in extension */
4602 if (c_ext == -1) {
4603 c_ext = 0;
4604 /* first, we have to count them */
4605 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4606 if (!yin->ns) {
4607 /* garbage */
4608 lyxml_free(mod->ctx, yin);
4609 continue;
4610 } else if (strcmp(yin->ns->value, LY_NSYIN)) {
4611 /* possible extension instance */
4612 c_ext++;
4613 } else {
4614 /* unexpected statement */
4615 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004616 return -1;
4617 }
Radek Krejci72b35992017-01-04 16:27:44 +01004618 }
4619 }
4620 if (c_ext) {
4621 (*ext)->ext = calloc(c_ext, sizeof *(*ext)->ext);
4622 if (!(*ext)->ext) {
4623 LOGMEM;
4624 return -1;
4625 }
4626 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
Radek Krejci07d0fb92017-01-13 14:11:05 +01004627 rc = lyp_yin_fill_ext(*ext, LYEXT_PAR_EXTINST, LYEXT_SUBSTMT_SELF, 0, (struct lys_module *)mod, yin,
Radek Krejci2b999ac2017-01-18 16:22:12 +01004628 &(*ext)->ext, (*ext)->ext_size, unres);
Radek Krejci72b35992017-01-04 16:27:44 +01004629 (*ext)->ext_size++;
4630 if (rc == -1) {
4631 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004632 }
4633 }
Radek Krejcie534c132016-11-23 13:32:31 +01004634 }
Radek Krejci72b35992017-01-04 16:27:44 +01004635
4636 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4637
Radek Krejcie534c132016-11-23 13:32:31 +01004638 } else {
4639 /* TODO YANG */
4640
4641 return -1;
4642 }
4643
4644 return EXIT_SUCCESS;
4645}
4646
Michal Vasko730dfdf2015-08-11 14:48:05 +02004647/**
Pavol Vican855ca622016-09-05 13:07:54 +02004648 * @brief Resolve (find) choice default case. Does not log.
4649 *
4650 * @param[in] choic Choice to use.
4651 * @param[in] dflt Name of the default case.
4652 *
4653 * @return Pointer to the default node or NULL.
4654 */
4655static struct lys_node *
4656resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4657{
4658 struct lys_node *child, *ret;
4659
4660 LY_TREE_FOR(choic->child, child) {
4661 if (child->nodetype == LYS_USES) {
4662 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4663 if (ret) {
4664 return ret;
4665 }
4666 }
4667
4668 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004669 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004670 return child;
4671 }
4672 }
4673
4674 return NULL;
4675}
4676
4677/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004678 * @brief Resolve uses, apply augments, refines. Logs directly.
4679 *
Michal Vaskobb211122015-08-19 14:03:11 +02004680 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004681 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004682 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004683 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004684 */
Michal Vasko184521f2015-09-24 13:14:26 +02004685static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004686resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004687{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004688 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004689 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004690 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004691 struct lys_node_leaflist *llist;
4692 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004693 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004694 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004695 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004696 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004697 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004698 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004699
Michal Vasko71e1aa82015-08-12 12:17:51 +02004700 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004701
4702 /* HACK just check that the grouping is resolved
4703 * - the higher byte in flags is always empty in grouping (no flags there apply to the groupings)
4704 * so we use it to count unresolved uses inside the grouping */
4705#if __BYTE_ORDER == __LITTLE_ENDIAN
4706 assert(!((uint8_t*)&uses->grp->flags)[1]);
4707#else
4708 assert(!((uint8_t*)&uses->grp->flags)[0]);
4709#endif
Michal Vasko71e1aa82015-08-12 12:17:51 +02004710
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004711 if (!uses->grp->child) {
4712 /* grouping without children, warning was already displayed */
4713 return EXIT_SUCCESS;
4714 }
4715
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004716 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004717 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01004718 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004719 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004720 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004721 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004722 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004723 }
Pavol Vican55abd332016-07-12 15:54:49 +02004724 /* test the name of siblings */
4725 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004726 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004727 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004728 }
4729 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004730 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004731
Michal Vaskodef0db12015-10-07 13:22:48 +02004732 /* we managed to copy the grouping, the rest must be possible to resolve */
4733
Pavol Vican855ca622016-09-05 13:07:54 +02004734 if (uses->refine_size) {
4735 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4736 if (!refine_nodes) {
4737 LOGMEM;
4738 goto fail;
4739 }
4740 }
4741
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004742 /* apply refines */
4743 for (i = 0; i < uses->refine_size; i++) {
4744 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004745 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004746 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004747 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004748 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004749 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004750 }
4751
Radek Krejci1d82ef62015-08-07 14:44:40 +02004752 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004753 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004754 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004755 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004756 }
Pavol Vican855ca622016-09-05 13:07:54 +02004757 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004758
4759 /* description on any nodetype */
4760 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004761 lydict_remove(ctx, node->dsc);
4762 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004763 }
4764
4765 /* reference on any nodetype */
4766 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004767 lydict_remove(ctx, node->ref);
4768 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004769 }
4770
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004771 /* config on any nodetype,
4772 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4773 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004774 node->flags &= ~LYS_CONFIG_MASK;
4775 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004776 }
4777
4778 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004779 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004780 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004781 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004782 leaf = (struct lys_node_leaf *)node;
4783
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004784 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004785 lydict_remove(ctx, leaf->dflt);
4786 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4787
4788 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004789 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4790 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004791 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004792 }
Radek Krejci200bf712016-08-16 17:11:04 +02004793 } else if (node->nodetype == LYS_LEAFLIST) {
4794 /* leaf-list */
4795 llist = (struct lys_node_leaflist *)node;
4796
4797 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004798 for (j = 0; j < llist->dflt_size; j++) {
4799 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004800 }
4801 free(llist->dflt);
4802
4803 /* copy the default set from refine */
4804 llist->dflt_size = rfn->dflt_size;
4805 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
Radek Krejci542ab142017-01-23 15:57:08 +01004806 for (j = 0; j < llist->dflt_size; j++) {
4807 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004808 }
4809
4810 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004811 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004812 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004813 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004814 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004815 }
4816 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004817 }
4818 }
4819
4820 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004821 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004822 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004823 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004824 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004825
4826 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004827 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004828 }
Pavol Vican855ca622016-09-05 13:07:54 +02004829 if (rfn->flags & LYS_MAND_TRUE) {
4830 /* check if node has default value */
4831 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4832 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4833 goto fail;
4834 }
4835 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4836 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4837 goto fail;
4838 }
4839 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004840 }
4841
4842 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004843 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4844 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4845 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004846 }
4847
4848 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004849 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004850 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004851 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004852 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004853 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004854 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004855 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004856 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004857 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004858 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004859 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004860 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004861 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004862 }
4863 }
4864
4865 /* must in leaf, leaf-list, list, container or anyxml */
4866 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004867 switch (node->nodetype) {
4868 case LYS_LEAF:
4869 old_size = &((struct lys_node_leaf *)node)->must_size;
4870 old_must = &((struct lys_node_leaf *)node)->must;
4871 break;
4872 case LYS_LEAFLIST:
4873 old_size = &((struct lys_node_leaflist *)node)->must_size;
4874 old_must = &((struct lys_node_leaflist *)node)->must;
4875 break;
4876 case LYS_LIST:
4877 old_size = &((struct lys_node_list *)node)->must_size;
4878 old_must = &((struct lys_node_list *)node)->must;
4879 break;
4880 case LYS_CONTAINER:
4881 old_size = &((struct lys_node_container *)node)->must_size;
4882 old_must = &((struct lys_node_container *)node)->must;
4883 break;
4884 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004885 case LYS_ANYDATA:
4886 old_size = &((struct lys_node_anydata *)node)->must_size;
4887 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004888 break;
4889 default:
4890 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004891 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004892 }
4893
4894 size = *old_size + rfn->must_size;
4895 must = realloc(*old_must, size * sizeof *rfn->must);
4896 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004897 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004898 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004899 }
Pavol Vican855ca622016-09-05 13:07:54 +02004900 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci77f22b22017-01-17 15:23:03 +01004901 must[j].ext_size = rfn[k].ext_size;
Radek Krejcifdc0d702017-01-23 15:58:38 +01004902 lys_ext_dup(ctx, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
4903 &must[j].ext, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004904 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4905 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4906 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4907 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4908 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004909 }
4910
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004911 *old_must = must;
4912 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004913
4914 /* check XPath dependencies again */
4915 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4916 goto fail;
4917 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004918 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004919
4920 /* if-feature in leaf, leaf-list, list, container or anyxml */
4921 if (rfn->iffeature_size) {
4922 old_size = &node->iffeature_size;
4923 old_iff = &node->iffeature;
4924
4925 size = *old_size + rfn->iffeature_size;
4926 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4927 if (!iff) {
4928 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004929 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004930 }
Pavol Vican855ca622016-09-05 13:07:54 +02004931 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4932 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004933 if (usize1) {
4934 /* there is something to duplicate */
4935 /* duplicate compiled expression */
4936 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4937 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004938 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004939
4940 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004941 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4942 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004943 }
4944 }
4945
4946 *old_iff = iff;
4947 *old_size = size;
4948 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004949 }
4950
4951 /* apply augments */
4952 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004953 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004954 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004955 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004956 }
4957 }
4958
Pavol Vican855ca622016-09-05 13:07:54 +02004959 /* check refines */
4960 for (i = 0; i < uses->refine_size; i++) {
4961 node = refine_nodes[i];
4962 rfn = &uses->refine[i];
4963
4964 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004965 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004966 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004967 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004968 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4969 (rfn->flags & LYS_CONFIG_W)) {
4970 /* setting config true under config false is prohibited */
4971 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004972 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004973 "changing config from 'false' to 'true' is prohibited while "
4974 "the target's parent is still config 'false'.");
4975 goto fail;
4976 }
4977
4978 /* inherit config change to the target children */
4979 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4980 if (rfn->flags & LYS_CONFIG_W) {
4981 if (iter->flags & LYS_CONFIG_SET) {
4982 /* config is set explicitely, go to next sibling */
4983 next = NULL;
4984 goto nextsibling;
4985 }
4986 } else { /* LYS_CONFIG_R */
4987 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4988 /* error - we would have config data under status data */
4989 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004990 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004991 "changing config from 'true' to 'false' is prohibited while the target "
4992 "has still a children with explicit config 'true'.");
4993 goto fail;
4994 }
4995 }
4996 /* change config */
4997 iter->flags &= ~LYS_CONFIG_MASK;
4998 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4999
5000 /* select next iter - modified LY_TREE_DFS_END */
5001 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
5002 next = NULL;
5003 } else {
5004 next = iter->child;
5005 }
5006nextsibling:
5007 if (!next) {
5008 /* try siblings */
5009 next = iter->next;
5010 }
5011 while (!next) {
5012 /* parent is already processed, go to its sibling */
5013 iter = lys_parent(iter);
5014
5015 /* no siblings, go back through parents */
5016 if (iter == node) {
5017 /* we are done, no next element to process */
5018 break;
5019 }
5020 next = iter->next;
5021 }
5022 }
5023 }
5024
5025 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005026 if (rfn->dflt_size) {
5027 if (node->nodetype == LYS_CHOICE) {
5028 /* choice */
5029 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
5030 rfn->dflt[0]);
5031 if (!((struct lys_node_choice *)node)->dflt) {
5032 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
5033 goto fail;
5034 }
5035 if (lyp_check_mandatory_choice(node)) {
5036 goto fail;
5037 }
Pavol Vican855ca622016-09-05 13:07:54 +02005038 }
5039 }
5040
5041 /* min/max-elements on list or leaf-list */
5042 if (node->nodetype == LYS_LIST) {
5043 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
5044 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5045 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5046 goto fail;
5047 }
5048 } else if (node->nodetype == LYS_LEAFLIST) {
5049 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
5050 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
5051 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
5052 goto fail;
5053 }
5054 }
5055
5056 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005057 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02005058 if (node->nodetype == LYS_LEAFLIST) {
5059 llist = (struct lys_node_leaflist *)node;
5060 if (llist->dflt_size && llist->min) {
5061 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
5062 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
5063 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
5064 goto fail;
5065 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005066 } else if (node->nodetype == LYS_LEAF) {
5067 leaf = (struct lys_node_leaf *)node;
5068 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
5069 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "mandatory", "refine");
5070 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
5071 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
5072 goto fail;
5073 }
Pavol Vican855ca622016-09-05 13:07:54 +02005074 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005075
Pavol Vican855ca622016-09-05 13:07:54 +02005076 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02005077 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02005078 for (parent = node->parent;
5079 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
5080 parent = parent->parent) {
5081 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
5082 /* stop also on presence containers */
5083 break;
5084 }
5085 }
5086 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
5087 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
5088 if (lyp_check_mandatory_choice(parent)) {
5089 goto fail;
5090 }
5091 }
5092 }
5093 }
5094 free(refine_nodes);
5095
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005096 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02005097
5098fail:
5099 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5100 lys_node_free(iter, NULL, 0);
5101 }
Pavol Vican855ca622016-09-05 13:07:54 +02005102 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005103 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005104}
5105
Radek Krejci018f1f52016-08-03 16:01:20 +02005106static int
5107identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
5108{
5109 int i;
5110
5111 assert(der && base);
5112
Radek Krejci018f1f52016-08-03 16:01:20 +02005113 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005114 /* create a set for backlinks if it does not exist */
5115 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005116 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005117 /* store backlink */
5118 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005119
Radek Krejci85a54be2016-10-20 12:39:56 +02005120 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005121 for (i = 0; i < base->base_size; i++) {
5122 if (identity_backlink_update(der, base->base[i])) {
5123 return EXIT_FAILURE;
5124 }
5125 }
5126
5127 return EXIT_SUCCESS;
5128}
5129
Michal Vasko730dfdf2015-08-11 14:48:05 +02005130/**
5131 * @brief Resolve base identity recursively. Does not log.
5132 *
5133 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005134 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005135 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005136 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005137 *
Radek Krejci219fa612016-08-15 10:36:51 +02005138 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005139 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005140static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005141resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005142 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005143{
Michal Vaskof02e3742015-08-05 16:27:02 +02005144 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005145 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005146
Radek Krejcicf509982015-12-15 09:22:44 +01005147 assert(ret);
5148
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005149 /* search module */
5150 for (i = 0; i < module->ident_size; i++) {
5151 if (!strcmp(basename, module->ident[i].name)) {
5152
5153 if (!ident) {
5154 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005155 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005156 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005157 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005158 }
5159
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005160 base = &module->ident[i];
5161 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005162 }
5163 }
5164
5165 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005166 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5167 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5168 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005169
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005170 if (!ident) {
5171 *ret = &module->inc[j].submodule->ident[i];
5172 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005173 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005174
5175 base = &module->inc[j].submodule->ident[i];
5176 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005177 }
5178 }
5179 }
5180
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005181matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005182 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005183 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005184 /* is it already completely resolved? */
5185 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005186 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005187 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5188
5189 /* simple check for circular reference,
5190 * the complete check is done as a side effect of using only completely
5191 * resolved identities (previous check of unres content) */
5192 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5193 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5194 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005195 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005196 }
5197
Radek Krejci06f64ed2016-08-15 11:07:44 +02005198 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005199 }
5200 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005201
Radek Krejcibabbff82016-02-19 13:31:37 +01005202 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005203 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005204 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005205 }
5206
Radek Krejci219fa612016-08-15 10:36:51 +02005207 /* base not found (maybe a forward reference) */
5208 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005209}
5210
Michal Vasko730dfdf2015-08-11 14:48:05 +02005211/**
5212 * @brief Resolve base identity. Logs directly.
5213 *
5214 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005215 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005216 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005217 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005218 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005219 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005220 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005221 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005222static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005223resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005224 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005225{
5226 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005227 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005228 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005229 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005230 struct lys_module *mod;
5231
5232 assert((ident && !type) || (!ident && type));
5233
5234 if (!type) {
5235 /* have ident to resolve */
5236 ret = &target;
5237 flags = ident->flags;
5238 mod = ident->module;
5239 } else {
5240 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005241 ++type->info.ident.count;
5242 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
5243 if (!type->info.ident.ref) {
5244 LOGMEM;
5245 return -1;
5246 }
5247
5248 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005249 flags = type->parent->flags;
5250 mod = type->parent->module;
5251 }
Michal Vaskof2006002016-04-21 16:28:15 +02005252 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005253
5254 /* search for the base identity */
5255 name = strchr(basename, ':');
5256 if (name) {
5257 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005258 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005259 name++;
5260
Michal Vasko2d851a92015-10-20 16:16:36 +02005261 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005262 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005263 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005264 }
5265 } else {
5266 name = basename;
5267 }
5268
Radek Krejcic071c542016-01-27 14:57:51 +01005269 /* get module where to search */
5270 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5271 if (!module) {
5272 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005273 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005274 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005275 }
5276
Radek Krejcic071c542016-01-27 14:57:51 +01005277 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005278 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5279 if (!rc) {
5280 assert(*ret);
5281
5282 /* check status */
5283 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5284 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5285 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005286 } else {
5287 if (ident) {
5288 ident->base[ident->base_size++] = *ret;
5289
5290 /* maintain backlinks to the derived identities */
5291 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
5292 }
Radek Krejci219fa612016-08-15 10:36:51 +02005293 }
5294 } else if (rc == EXIT_FAILURE) {
5295 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005296 if (type) {
5297 --type->info.ident.count;
5298 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005299 }
5300
Radek Krejci219fa612016-08-15 10:36:51 +02005301 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005302}
5303
Michal Vasko730dfdf2015-08-11 14:48:05 +02005304/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005305 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005306 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005307 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005308 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005309 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005310 *
5311 * @return Pointer to the identity resolvent, NULL on error.
5312 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005313struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005314resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005315{
Radek Krejci639491e2016-12-05 13:30:42 +01005316 const char *mod_name, *name, *mod_name_iter;
Radek Krejci85a54be2016-10-20 12:39:56 +02005317 int mod_name_len, rc, i;
5318 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005319 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005320
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005321 assert(type && ident_name && node);
5322
Michal Vaskof2d43962016-09-02 11:10:16 +02005323 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005324 return NULL;
5325 }
5326
Michal Vaskoc633ca02015-08-21 14:03:51 +02005327 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005328 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005329 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005330 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005331 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005332 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005333 return NULL;
5334 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005335 if (!mod_name) {
5336 /* no prefix, identity must be defined in the same module as node */
Radek Krejci639491e2016-12-05 13:30:42 +01005337 mod_name = lys_main_module(node->schema->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005338 mod_name_len = strlen(mod_name);
5339 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005340
Michal Vaskof2d43962016-09-02 11:10:16 +02005341 /* go through all the bases in all the derived types */
5342 while (type->der) {
5343 for (i = 0; i < type->info.ident.count; ++i) {
5344 cur = type->info.ident.ref[i];
Radek Krejci639491e2016-12-05 13:30:42 +01005345 mod_name_iter = lys_main_module(cur->module)->name;
Radek Krejcif32c5f62016-12-05 09:27:38 +01005346 if (!strcmp(cur->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005347 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Michal Vaskof2d43962016-09-02 11:10:16 +02005348 goto match;
5349 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005350
Radek Krejci85a54be2016-10-20 12:39:56 +02005351 if (cur->der) {
5352 /* there are also some derived identities */
5353 for (u = 0; u < cur->der->number; u++) {
5354 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci639491e2016-12-05 13:30:42 +01005355 mod_name_iter = lys_main_module(der->module)->name;
Radek Krejci85a54be2016-10-20 12:39:56 +02005356 if (!strcmp(der->name, name) &&
Radek Krejci639491e2016-12-05 13:30:42 +01005357 !strncmp(mod_name_iter, mod_name, mod_name_len) && !mod_name_iter[mod_name_len]) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005358 /* we have match */
5359 cur = der;
5360 goto match;
5361 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005362 }
5363 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005364 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005365 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005366 }
5367
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005368 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005369 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005370
5371match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005372 for (i = 0; i < cur->iffeature_size; i++) {
5373 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005374 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005375 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Identity \"%s\" is disabled by its if-feature condition.", cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005376 return NULL;
5377 }
5378 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005379 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005380}
5381
Michal Vasko730dfdf2015-08-11 14:48:05 +02005382/**
Michal Vaskobb211122015-08-19 14:03:11 +02005383 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005384 *
Michal Vaskobb211122015-08-19 14:03:11 +02005385 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005386 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005387 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005388 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005389 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005390static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005391resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005392{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005393 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005394 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005395
Radek Krejci6ff885d2017-01-03 14:06:22 +01005396 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
5397 * in some uses. When we see such a uses, the grouping's higher byte of the flags member (not used in
5398 * grouping) is used to store number of so far unresolved uses. The grouping cannot be used unless this
5399 * counter is decreased back to 0. To remember that the uses already increased grouping's counter, the
Radek Krejci010e54b2016-03-15 09:40:34 +01005400 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005401 for (par_grp = lys_parent((struct lys_node *)uses); par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
Michal Vaskoe91afce2015-08-12 12:21:00 +02005402
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005403 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005404 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5405 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005406 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005407 return -1;
5408 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005409 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005410 return -1;
5411 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005412 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005413 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5414 * (and smaller flags - it uses only a limited set of flags)
5415 */
Radek Krejci6ff885d2017-01-03 14:06:22 +01005416#if __BYTE_ORDER == __LITTLE_ENDIAN
5417 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
5418#else
5419 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
5420#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005421 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005422 }
Michal Vasko92981a62016-10-14 10:25:16 +02005423 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005424 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005425 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005426 }
5427
Radek Krejci6ff885d2017-01-03 14:06:22 +01005428#if __BYTE_ORDER == __LITTLE_ENDIAN
5429 if (((uint8_t*)&uses->grp->flags)[1]) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005430 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01005431 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
5432#else
5433 if (((uint8_t*)&uses->grp->flags)[0]) {
5434 if (par_grp && !(uses->flags & LYS_USESGRP)) {
5435 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
5436#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005437 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005438 } else {
5439 /* instantiate grouping only when it is completely resolved */
5440 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005441 }
Michal Vasko92981a62016-10-14 10:25:16 +02005442 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005443 return EXIT_FAILURE;
5444 }
5445
Radek Krejci48464ed2016-03-17 15:44:09 +01005446 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005447 if (!rc) {
5448 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005449 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01005450#if __BYTE_ORDER == __LITTLE_ENDIAN
5451 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]) {;
5452#else
5453 if (!((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]) {;
5454#endif
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005455 LOGINT;
5456 return -1;
5457 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01005458#if __BYTE_ORDER == __LITTLE_ENDIAN
5459 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]--;
5460#else
5461 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]--;
5462#endif
Radek Krejci010e54b2016-03-15 09:40:34 +01005463 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005464 }
Radek Krejcicf509982015-12-15 09:22:44 +01005465
5466 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005467 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005468 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005469 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005470 return -1;
5471 }
5472
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005473 return EXIT_SUCCESS;
5474 }
5475
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005476 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005477}
5478
Michal Vasko730dfdf2015-08-11 14:48:05 +02005479/**
Michal Vasko9957e592015-08-17 15:04:09 +02005480 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005481 *
Michal Vaskobb211122015-08-19 14:03:11 +02005482 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005483 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005484 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005485 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005486 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005487static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005488resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005489{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005490 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005491 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005492
5493 for (i = 0; i < list->keys_size; ++i) {
Radek Krejci5c08a992016-11-02 13:30:04 +01005494 if (!list->child) {
5495 /* no child, possible forward reference */
5496 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5497 return EXIT_FAILURE;
5498 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005499 /* get the key name */
5500 if ((value = strpbrk(keys_str, " \t\n"))) {
5501 len = value - keys_str;
5502 while (isspace(value[0])) {
5503 value++;
5504 }
5505 } else {
5506 len = strlen(keys_str);
5507 }
5508
Michal Vasko0f99d3e2017-01-10 10:50:40 +01005509 rc = lys_get_data_sibling(lys_node_module((struct lys_node *)list), list->child, keys_str, len, LYS_LEAF,
5510 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005511 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005512 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5513 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005514 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005515
Radek Krejci48464ed2016-03-17 15:44:09 +01005516 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005517 /* check_key logs */
5518 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005519 }
5520
Radek Krejcicf509982015-12-15 09:22:44 +01005521 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005522 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005523 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5524 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005525 return -1;
5526 }
5527
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005528 /* prepare for next iteration */
5529 while (value && isspace(value[0])) {
5530 value++;
5531 }
5532 keys_str = value;
5533 }
5534
Michal Vaskof02e3742015-08-05 16:27:02 +02005535 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005536}
5537
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005538/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005539 * @brief Resolve (check) all must conditions of \p node.
5540 * Logs directly.
5541 *
5542 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005543 * @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 +02005544 *
5545 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5546 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005547static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005548resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005549{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005550 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005551 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005552 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005553 struct lys_restr *must;
5554 struct lyxp_set set;
5555
5556 assert(node);
5557 memset(&set, 0, sizeof set);
5558
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005559 if (inout_parent) {
5560 for (schema = lys_parent(node->schema);
5561 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5562 schema = lys_parent(schema));
5563 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5564 LOGINT;
5565 return -1;
5566 }
5567 must_size = ((struct lys_node_inout *)schema)->must_size;
5568 must = ((struct lys_node_inout *)schema)->must;
5569
Michal Vasko3cfa3182017-01-17 10:00:58 +01005570 node_flags = schema->flags;
5571
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005572 /* context node is the RPC/action */
5573 node = node->parent;
5574 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5575 LOGINT;
5576 return -1;
5577 }
5578 } else {
5579 switch (node->schema->nodetype) {
5580 case LYS_CONTAINER:
5581 must_size = ((struct lys_node_container *)node->schema)->must_size;
5582 must = ((struct lys_node_container *)node->schema)->must;
5583 break;
5584 case LYS_LEAF:
5585 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5586 must = ((struct lys_node_leaf *)node->schema)->must;
5587 break;
5588 case LYS_LEAFLIST:
5589 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5590 must = ((struct lys_node_leaflist *)node->schema)->must;
5591 break;
5592 case LYS_LIST:
5593 must_size = ((struct lys_node_list *)node->schema)->must_size;
5594 must = ((struct lys_node_list *)node->schema)->must;
5595 break;
5596 case LYS_ANYXML:
5597 case LYS_ANYDATA:
5598 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5599 must = ((struct lys_node_anydata *)node->schema)->must;
5600 break;
5601 case LYS_NOTIF:
5602 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5603 must = ((struct lys_node_notif *)node->schema)->must;
5604 break;
5605 default:
5606 must_size = 0;
5607 break;
5608 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005609
5610 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005611 }
5612
5613 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005614 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005615 return -1;
5616 }
5617
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005618 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005619
Michal Vasko8146d4c2016-05-09 15:50:29 +02005620 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005621 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005622 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5623 } else {
5624 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5625 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005626 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005627 }
5628 if (must[i].eapptag) {
5629 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5630 }
5631 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005632 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005633 }
5634 }
5635
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005636 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005637}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005638
Michal Vaskobf19d252015-10-08 15:39:17 +02005639/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005640 * @brief Resolve (find) when condition schema context node. Does not log.
5641 *
5642 * @param[in] schema Schema node with the when condition.
5643 * @param[out] ctx_snode When schema context node.
5644 * @param[out] ctx_snode_type Schema context node type.
5645 */
5646void
5647resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5648{
5649 const struct lys_node *sparent;
5650
5651 /* find a not schema-only node */
5652 *ctx_snode_type = LYXP_NODE_ELEM;
5653 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5654 if (schema->nodetype == LYS_AUGMENT) {
5655 sparent = ((struct lys_node_augment *)schema)->target;
5656 } else {
5657 sparent = schema->parent;
5658 }
5659 if (!sparent) {
5660 /* context node is the document root (fake root in our case) */
5661 if (schema->flags & LYS_CONFIG_W) {
5662 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5663 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005664 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005665 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005666 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005667 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005668 break;
5669 }
5670 schema = sparent;
5671 }
5672
5673 *ctx_snode = (struct lys_node *)schema;
5674}
5675
5676/**
Michal Vaskocf024702015-10-08 15:01:42 +02005677 * @brief Resolve (find) when condition context node. Does not log.
5678 *
5679 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005680 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005681 * @param[out] ctx_node Context node.
5682 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005683 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005684 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005685 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005686static int
5687resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5688 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005689{
Michal Vaskocf024702015-10-08 15:01:42 +02005690 struct lyd_node *parent;
5691 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005692 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005693 uint16_t i, data_depth, schema_depth;
5694
Michal Vasko508a50d2016-09-07 14:50:33 +02005695 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005696
Michal Vaskofe989752016-09-08 08:47:26 +02005697 if (node_type == LYXP_NODE_ELEM) {
5698 /* standard element context node */
5699 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5700 for (sparent = schema, schema_depth = 0;
5701 sparent;
5702 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5703 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5704 ++schema_depth;
5705 }
Michal Vaskocf024702015-10-08 15:01:42 +02005706 }
Michal Vaskofe989752016-09-08 08:47:26 +02005707 if (data_depth < schema_depth) {
5708 return -1;
5709 }
Michal Vaskocf024702015-10-08 15:01:42 +02005710
Michal Vasko956e8542016-08-26 09:43:35 +02005711 /* find the corresponding data node */
5712 for (i = 0; i < data_depth - schema_depth; ++i) {
5713 node = node->parent;
5714 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005715 if (node->schema != schema) {
5716 return -1;
5717 }
Michal Vaskofe989752016-09-08 08:47:26 +02005718 } else {
5719 /* root context node */
5720 while (node->parent) {
5721 node = node->parent;
5722 }
5723 while (node->prev->next) {
5724 node = node->prev;
5725 }
Michal Vaskocf024702015-10-08 15:01:42 +02005726 }
5727
Michal Vaskoa59495d2016-08-22 09:18:58 +02005728 *ctx_node = node;
5729 *ctx_node_type = node_type;
5730 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005731}
5732
Michal Vasko76c3bd32016-08-24 16:02:52 +02005733/**
5734 * @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 +01005735 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005736 *
5737 * @param[in] snode Schema node, whose children instances need to be unlinked.
5738 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5739 * it is moved to point to another sibling still in the original tree.
5740 * @param[in,out] ctx_node When context node, adjusted if needed.
5741 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5742 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5743 * Ordering may change, but there will be no semantic change.
5744 *
5745 * @return EXIT_SUCCESS on success, -1 on error.
5746 */
5747static int
5748resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5749 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5750{
5751 struct lyd_node *next, *elem;
5752
5753 switch (snode->nodetype) {
5754 case LYS_AUGMENT:
5755 case LYS_USES:
5756 case LYS_CHOICE:
5757 case LYS_CASE:
5758 LY_TREE_FOR(snode->child, snode) {
5759 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5760 return -1;
5761 }
5762 }
5763 break;
5764 case LYS_CONTAINER:
5765 case LYS_LIST:
5766 case LYS_LEAF:
5767 case LYS_LEAFLIST:
5768 case LYS_ANYXML:
5769 case LYS_ANYDATA:
5770 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5771 if (elem->schema == snode) {
5772
5773 if (elem == *ctx_node) {
5774 /* We are going to unlink our context node! This normally cannot happen,
5775 * but we use normal top-level data nodes for faking a document root node,
5776 * so if this is the context node, we just use the next top-level node.
5777 * Additionally, it can even happen that there are no top-level data nodes left,
5778 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5779 * lyxp_eval() can handle this special situation.
5780 */
5781 if (ctx_node_type == LYXP_NODE_ELEM) {
5782 LOGINT;
5783 return -1;
5784 }
5785
5786 if (elem->prev == elem) {
5787 /* unlinking last top-level element, use an empty data tree */
5788 *ctx_node = NULL;
5789 } else {
5790 /* in this case just use the previous/last top-level data node */
5791 *ctx_node = elem->prev;
5792 }
5793 } else if (elem == *node) {
5794 /* We are going to unlink the currently processed node. This does not matter that
5795 * much, but we would lose access to the original data tree, so just move our
5796 * pointer somewhere still inside it.
5797 */
5798 if ((*node)->prev != *node) {
5799 *node = (*node)->prev;
5800 } else {
5801 /* the processed node with sibings were all unlinked, oh well */
5802 *node = NULL;
5803 }
5804 }
5805
5806 /* temporarily unlink the node */
5807 lyd_unlink(elem);
5808 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005809 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005810 LOGINT;
5811 return -1;
5812 }
5813 } else {
5814 *unlinked_nodes = elem;
5815 }
5816
5817 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5818 /* there can be only one instance */
5819 break;
5820 }
5821 }
5822 }
5823 break;
5824 default:
5825 LOGINT;
5826 return -1;
5827 }
5828
5829 return EXIT_SUCCESS;
5830}
5831
5832/**
5833 * @brief Relink the unlinked nodes back.
5834 *
5835 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5836 * we simply need a sibling from the original data tree.
5837 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5838 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5839 * or the sibling of \p unlinked_nodes.
5840 *
5841 * @return EXIT_SUCCESS on success, -1 on error.
5842 */
5843static int
5844resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5845{
5846 struct lyd_node *elem;
5847
5848 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vaskode1feeb2016-12-20 14:48:42 +01005849 lyd_unlink(elem);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005850 if (ctx_node_type == LYXP_NODE_ELEM) {
5851 if (lyd_insert(node, elem)) {
5852 return -1;
5853 }
5854 } else {
5855 if (lyd_insert_after(node, elem)) {
5856 return -1;
5857 }
5858 }
5859 }
5860
5861 return EXIT_SUCCESS;
5862}
5863
Radek Krejci03b71f72016-03-16 11:10:09 +01005864int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005865resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005866{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005867 int ret = 0;
5868 uint8_t must_size;
5869 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005870
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005871 assert(node);
5872
5873 schema = node->schema;
5874
5875 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005876 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005877 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005878 must_size = ((struct lys_node_container *)schema)->must_size;
5879 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005880 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005881 must_size = ((struct lys_node_leaf *)schema)->must_size;
5882 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005883 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005884 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5885 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005886 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005887 must_size = ((struct lys_node_list *)schema)->must_size;
5888 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005889 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005890 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005891 must_size = ((struct lys_node_anydata *)schema)->must_size;
5892 break;
5893 case LYS_NOTIF:
5894 must_size = ((struct lys_node_notif *)schema)->must_size;
5895 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005896 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005897 must_size = 0;
5898 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005899 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005900
5901 if (must_size) {
5902 ++ret;
5903 }
5904
5905 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5906 if (!node->prev->next) {
5907 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5908 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5909 ret += 0x2;
5910 }
5911 }
5912
5913 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005914}
5915
5916int
Radek Krejci46165822016-08-26 14:06:27 +02005917resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005918{
Radek Krejci46165822016-08-26 14:06:27 +02005919 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005920
Radek Krejci46165822016-08-26 14:06:27 +02005921 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005922
Radek Krejci46165822016-08-26 14:06:27 +02005923 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005924 return 1;
5925 }
5926
Radek Krejci46165822016-08-26 14:06:27 +02005927 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005928 goto check_augment;
5929
Radek Krejci46165822016-08-26 14:06:27 +02005930 while (parent) {
5931 /* stop conditions */
5932 if (!mode) {
5933 /* stop on node that can be instantiated in data tree */
5934 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5935 break;
5936 }
5937 } else {
5938 /* stop on the specified node */
5939 if (parent == stop) {
5940 break;
5941 }
5942 }
5943
5944 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005945 return 1;
5946 }
5947check_augment:
5948
5949 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005950 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005951 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005952 }
5953 parent = lys_parent(parent);
5954 }
5955
5956 return 0;
5957}
5958
Michal Vaskocf024702015-10-08 15:01:42 +02005959/**
5960 * @brief Resolve (check) all when conditions relevant for \p node.
5961 * Logs directly.
5962 *
5963 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005964 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005965 * @return
5966 * -1 - error, ly_errno is set
5967 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005968 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005969 * 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 +02005970 */
Radek Krejci46165822016-08-26 14:06:27 +02005971int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005972resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005973{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005974 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005975 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005976 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005977 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005978 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005979
5980 assert(node);
5981 memset(&set, 0, sizeof set);
5982
5983 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005984 /* make the node dummy for the evaluation */
5985 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005986 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5987 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005988 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005989 if (rc) {
5990 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005991 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005992 }
Radek Krejci51093642016-03-29 10:14:59 +02005993 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005994 }
5995
Radek Krejci03b71f72016-03-16 11:10:09 +01005996 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005997 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005998 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005999 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006000 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006001 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6002 ((struct lys_node_container *)node->schema)->when->cond);
6003 } else {
6004 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
6005 goto cleanup;
6006 }
Michal Vaskocf024702015-10-08 15:01:42 +02006007 }
Radek Krejci51093642016-03-29 10:14:59 +02006008
6009 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006010 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006011 }
6012
Michal Vasko90fc2a32016-08-24 15:58:58 +02006013 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02006014 goto check_augment;
6015
6016 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02006017 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
6018 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02006019 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006020 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006021 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006022 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006023 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006024 }
6025 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006026
6027 unlinked_nodes = NULL;
6028 /* we do not want our node pointer to change */
6029 tmp_node = node;
6030 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6031 if (rc) {
6032 goto cleanup;
6033 }
6034
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006035 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6036 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006037
6038 if (unlinked_nodes && ctx_node) {
6039 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6040 rc = -1;
6041 goto cleanup;
6042 }
6043 }
6044
Radek Krejci03b71f72016-03-16 11:10:09 +01006045 if (rc) {
6046 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006047 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006048 }
Radek Krejci51093642016-03-29 10:14:59 +02006049 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006050 }
6051
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006052 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006053 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006054 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006055 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006056 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6057 ((struct lys_node_uses *)sparent)->when->cond);
6058 } else {
6059 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6060 goto cleanup;
6061 }
Michal Vaskocf024702015-10-08 15:01:42 +02006062 }
Radek Krejci51093642016-03-29 10:14:59 +02006063
6064 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006065 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006066 }
6067
6068check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006069 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006070 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006071 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006072 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006073 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006074 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006075 }
6076 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006077
6078 unlinked_nodes = NULL;
6079 tmp_node = node;
6080 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6081 if (rc) {
6082 goto cleanup;
6083 }
6084
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006085 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6086 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006087
6088 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6089 * so the tree did not actually change and there is nothing for us to do
6090 */
6091 if (unlinked_nodes && ctx_node) {
6092 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6093 rc = -1;
6094 goto cleanup;
6095 }
6096 }
6097
Radek Krejci03b71f72016-03-16 11:10:09 +01006098 if (rc) {
6099 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006100 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006101 }
Radek Krejci51093642016-03-29 10:14:59 +02006102 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006103 }
6104
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006105 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006106 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006107 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006108 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006109 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006110 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006111 } else {
6112 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6113 goto cleanup;
6114 }
Michal Vaskocf024702015-10-08 15:01:42 +02006115 }
Radek Krejci51093642016-03-29 10:14:59 +02006116
6117 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006118 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006119 }
6120
Michal Vasko90fc2a32016-08-24 15:58:58 +02006121 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006122 }
6123
Radek Krejci0b7704f2016-03-18 12:16:14 +01006124 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006125
Radek Krejci51093642016-03-29 10:14:59 +02006126cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006127 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006128 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006129
Radek Krejci46165822016-08-26 14:06:27 +02006130 if (result) {
6131 if (node->when_status & LYD_WHEN_TRUE) {
6132 *result = 1;
6133 } else {
6134 *result = 0;
6135 }
6136 }
6137
Radek Krejci51093642016-03-29 10:14:59 +02006138 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006139}
6140
Radek Krejcicbb473e2016-09-16 14:48:32 +02006141static int
6142check_leafref_features(struct lys_type *type)
6143{
6144 struct lys_node *iter;
6145 struct ly_set *src_parents, *trg_parents, *features;
6146 unsigned int i, j, size, x;
6147 int ret = EXIT_SUCCESS;
6148
6149 assert(type->parent);
6150
6151 src_parents = ly_set_new();
6152 trg_parents = ly_set_new();
6153 features = ly_set_new();
6154
6155 /* get parents chain of source (leafref) */
6156 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
6157 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6158 continue;
6159 }
6160 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6161 }
6162 /* get parents chain of target */
6163 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
6164 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6165 continue;
6166 }
6167 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6168 }
6169
6170 /* compare the features used in if-feature statements in the rest of both
6171 * chains of parents. The set of features used for target must be a subset
6172 * of features used for the leafref. This is not a perfect, we should compare
6173 * the truth tables but it could require too much resources, so we simplify that */
6174 for (i = 0; i < src_parents->number; i++) {
6175 iter = src_parents->set.s[i]; /* shortcut */
6176 if (!iter->iffeature_size) {
6177 continue;
6178 }
6179 for (j = 0; j < iter->iffeature_size; j++) {
6180 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6181 for (; size; size--) {
6182 if (!iter->iffeature[j].features[size - 1]) {
6183 /* not yet resolved feature, postpone this check */
6184 ret = EXIT_FAILURE;
6185 goto cleanup;
6186 }
6187 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6188 }
6189 }
6190 }
6191 x = features->number;
6192 for (i = 0; i < trg_parents->number; i++) {
6193 iter = trg_parents->set.s[i]; /* shortcut */
6194 if (!iter->iffeature_size) {
6195 continue;
6196 }
6197 for (j = 0; j < iter->iffeature_size; j++) {
6198 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6199 for (; size; size--) {
6200 if (!iter->iffeature[j].features[size - 1]) {
6201 /* not yet resolved feature, postpone this check */
6202 ret = EXIT_FAILURE;
6203 goto cleanup;
6204 }
6205 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6206 /* the feature is not present in features set of target's parents chain */
6207 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006208 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006209 "Leafref is not conditional based on \"%s\" feature as its target.",
6210 iter->iffeature[j].features[size - 1]->name);
6211 ret = -1;
6212 goto cleanup;
6213 }
6214 }
6215 }
6216 }
6217
6218cleanup:
6219 ly_set_free(features);
6220 ly_set_free(src_parents);
6221 ly_set_free(trg_parents);
6222
6223 return ret;
6224}
6225
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006226/**
Michal Vaskobb211122015-08-19 14:03:11 +02006227 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006228 *
6229 * @param[in] mod Main module.
6230 * @param[in] item Item to resolve. Type determined by \p type.
6231 * @param[in] type Type of the unresolved item.
6232 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006233 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006234 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006235 *
6236 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6237 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006238static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006239resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006240 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006241{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006242 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02006243 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
6244 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006245 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006246 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006247 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006248
Radek Krejcic79c6b12016-07-26 15:11:49 +02006249 struct ly_set *refs, *procs;
6250 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006251 struct lys_ident *ident;
6252 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006253 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006254 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006255 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006256 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006257 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006258 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006259 struct lys_ext_instance *ext, **extlist;
6260 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006261
6262 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006263 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006264 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006265 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006266 ident = item;
6267
Radek Krejci018f1f52016-08-03 16:01:20 +02006268 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006269 break;
6270 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006271 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006272 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006273 stype = item;
6274
Radek Krejci018f1f52016-08-03 16:01:20 +02006275 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006276 break;
6277 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006278 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006279 stype = item;
6280
Radek Krejci2f12f852016-01-08 12:59:57 +01006281 /* HACK - when there is no parent, we are in top level typedef and in that
6282 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
6283 * know it via tpdf_flag */
6284 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01006285 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01006286 node = (struct lys_node *)stype->parent;
6287 }
6288
Radek Krejci27fe55e2016-09-13 17:13:35 +02006289 if (!lys_node_module(node)->implemented) {
6290 /* not implemented module, don't bother with resolving the leafref
Radek Krejci990af1f2016-11-09 13:53:36 +01006291 * if the module is set to be implemented, the path will be resolved then */
Radek Krejci27fe55e2016-09-13 17:13:35 +02006292 rc = 0;
6293 break;
6294 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006295 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01006296 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02006297 if (!tpdf_flag && !rc) {
6298 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006299 /* check if leafref and its target are under a common if-features */
6300 rc = check_leafref_features(stype);
6301 if (rc) {
6302 break;
6303 }
6304
Radek Krejci46c4cd72016-01-21 15:13:52 +01006305 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02006306 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6307 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01006308 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006309 }
6310
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006311 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006312 case UNRES_TYPE_DER_TPDF:
6313 tpdf_flag = 1;
6314 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006315 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006316 /* parent */
6317 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006318 stype = item;
6319
Michal Vasko88c29542015-11-27 14:57:53 +01006320 /* HACK type->der is temporarily unparsed type statement */
6321 yin = (struct lyxml_elem *)stype->der;
6322 stype->der = NULL;
6323
Pavol Vicana0e4e672016-02-24 12:20:04 +01006324 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6325 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006326 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006327
6328 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006329 /* may try again later */
6330 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006331 } else {
6332 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006333 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006334 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006335 }
6336
Michal Vasko88c29542015-11-27 14:57:53 +01006337 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006338 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006339 if (!rc) {
6340 /* we need to always be able to free this, it's safe only in this case */
6341 lyxml_free(mod->ctx, yin);
6342 } else {
6343 /* may try again later, put all back how it was */
6344 stype->der = (struct lys_tpdf *)yin;
6345 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006346 }
Radek Krejcic13db382016-08-16 10:52:42 +02006347 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006348 /* it does not make sense to have leaf-list of empty type */
6349 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
6350 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6351 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006352 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006353 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6354 * by uses statement until the type is resolved. We do that the same way as uses statements inside
6355 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
6356 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
Radek Krejci9b6aad22016-09-20 15:55:51 +02006357 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006358 * of the type's base member. */
6359 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6360 if (par_grp) {
Radek Krejci6ff885d2017-01-03 14:06:22 +01006361#if __BYTE_ORDER == __LITTLE_ENDIAN
6362 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[1]++;
6363#else
6364 ((uint8_t*)&((struct lys_node_grp *)par_grp)->flags)[0]++;
6365#endif
Radek Krejci9b6aad22016-09-20 15:55:51 +02006366 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006367 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006368 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006369 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006370 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006371 iff_data = str_snode;
6372 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006373 if (!rc) {
6374 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006375 if (iff_data->infeature) {
6376 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6377 feat = *((struct lys_feature **)item);
6378 if (!feat->depfeatures) {
6379 feat->depfeatures = ly_set_new();
6380 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006381 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006382 }
6383 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006384 lydict_remove(mod->ctx, iff_data->fname);
6385 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006386 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006387 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006388 case UNRES_FEATURE:
6389 feat = (struct lys_feature *)item;
6390
6391 if (feat->iffeature_size) {
6392 refs = ly_set_new();
6393 procs = ly_set_new();
6394 ly_set_add(procs, feat, 0);
6395
6396 while (procs->number) {
6397 ref = procs->set.g[procs->number - 1];
6398 ly_set_rm_index(procs, procs->number - 1);
6399
6400 for (i = 0; i < ref->iffeature_size; i++) {
6401 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6402 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006403 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006404 if (ref->iffeature[i].features[j - 1] == feat) {
6405 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6406 goto featurecheckdone;
6407 }
6408
6409 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6410 k = refs->number;
6411 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6412 /* not yet seen feature, add it for processing */
6413 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6414 }
6415 }
6416 } else {
6417 /* forward reference */
6418 rc = EXIT_FAILURE;
6419 goto featurecheckdone;
6420 }
6421 }
6422
6423 }
6424 }
6425 rc = EXIT_SUCCESS;
6426
6427featurecheckdone:
6428 ly_set_free(refs);
6429 ly_set_free(procs);
6430 }
6431
6432 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006433 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006434 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006435 break;
6436 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006437 stype = item;
6438
Radek Krejci51673202016-11-01 17:00:32 +01006439 rc = check_default(stype, (const char **)str_snode, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006440 break;
6441 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006442 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006443 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006444 choic = item;
6445
Radek Krejcie00d2312016-08-12 15:27:49 +02006446 if (!choic->dflt) {
6447 choic->dflt = resolve_choice_dflt(choic, expr);
6448 }
Michal Vasko7955b362015-09-04 14:18:15 +02006449 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006450 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006451 } else {
6452 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006453 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 break;
6455 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006456 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006457 break;
6458 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006459 unique_info = (struct unres_list_uniq *)item;
6460 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006461 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006462 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006463 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006464 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006465 case UNRES_XPATH:
6466 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006467 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006468 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006469 case UNRES_EXT:
6470 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006471 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006472 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006473 if (!rc) {
6474 if (ext_data->datatype == LYS_IN_YIN) {
6475 /* YIN */
6476 lyxml_free(mod->ctx, ext_data->data.yin);
6477 } else {
6478 /* TODO YANG */
6479 free(ext_data->data.yang);
6480 }
Radek Krejci80056d52017-01-05 13:13:33 +01006481
6482 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006483 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006484 if (eplugin) {
6485 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006486 u = malloc(sizeof *u);
6487 (*u) = ext_data->ext_index;
6488 unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u);
Radek Krejci80056d52017-01-05 13:13:33 +01006489 }
6490 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006491
6492 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006493 }
6494 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006495 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006496 u = (uint8_t *)str_snode;
6497 ext = (*(struct lys_ext_instance ***)item)[*u];
6498 free(u);
6499
Radek Krejci80056d52017-01-05 13:13:33 +01006500 eplugin = ext->def->plugin;
6501
6502 /* inherit */
6503 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6504 root = (struct lys_node *)ext->parent;
6505 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6506 LY_TREE_DFS_BEGIN(root->child, next, node) {
6507 /* first, check if the node already contain instance of the same extension,
6508 * in such a case we won't inherit. In case the node was actually defined as
6509 * augment data, we are supposed to check the same way also the augment node itself */
6510 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6511 goto inherit_dfs_sibling;
6512 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6513 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6514 goto inherit_dfs_sibling;
6515 }
6516
6517 if (eplugin->check_inherit) {
6518 /* we have a callback to check the inheritance, use it */
6519 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6520 case 0:
6521 /* yes - continue with the inheriting code */
6522 break;
6523 case 1:
6524 /* no - continue with the node's sibling */
6525 goto inherit_dfs_sibling;
6526 case 2:
6527 /* no, but continue with the children, just skip the inheriting code for this node */
6528 goto inherit_dfs_child;
6529 default:
6530 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6531 ext->def->module->name, ext->def->name, rc);
6532 }
6533 }
6534
6535 /* inherit the extension */
6536 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
6537 if (!extlist) {
6538 LOGMEM;
6539 return -1;
6540 }
6541 extlist[node->ext_size] = malloc(sizeof **extlist);
6542 if (!extlist[node->ext_size]) {
6543 LOGMEM;
6544 node->ext = extlist;
6545 return -1;
6546 }
6547 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6548 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6549
6550 node->ext = extlist;
6551 node->ext_size++;
6552
6553inherit_dfs_child:
6554 /* modification of - select element for the next run - children first */
6555 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6556 next = NULL;
6557 } else {
6558 next = node->child;
6559 }
6560 if (!next) {
6561inherit_dfs_sibling:
6562 /* no children, try siblings */
6563 next = node->next;
6564 }
6565 while (!next) {
6566 /* go to the parent */
6567 node = lys_parent(node);
6568
6569 /* we are done if we are back in the root (the starter's parent */
6570 if (node == root) {
6571 break;
6572 }
6573
6574 /* parent is already processed, go to its sibling */
6575 next = node->next;
6576 }
6577 }
6578 }
6579 }
6580
6581 /* final check */
6582 if (eplugin->check_result) {
6583 if ((*eplugin->check_result)(ext)) {
6584 return -1;
6585 }
6586 }
6587
6588 rc = 0;
6589 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006590 default:
6591 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006592 break;
6593 }
6594
Radek Krejci54081ce2016-08-12 15:21:47 +02006595 if (has_str && !rc) {
6596 /* the string is no more needed in case of success.
6597 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006598 lydict_remove(mod->ctx, str_snode);
6599 }
6600
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006601 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006602}
6603
Michal Vaskof02e3742015-08-05 16:27:02 +02006604/* logs directly */
6605static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006606print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006607{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006608 struct lyxml_elem *xml;
6609 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006610 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006611 const char *name = NULL;
6612 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006613
Michal Vaskof02e3742015-08-05 16:27:02 +02006614 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006615 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006616 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006617 break;
6618 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006619 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006620 break;
6621 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006622 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6623 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006624 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006625 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006626 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006627 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6628 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006629 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006630 } else {
6631 LY_TREE_FOR(xml->attr, attr) {
6632 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006633 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006634 break;
6635 }
6636 }
6637 assert(attr);
6638 }
Radek Krejcie534c132016-11-23 13:32:31 +01006639 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006640 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006641 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006642 iff_data = str_node;
6643 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006644 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006645 case UNRES_FEATURE:
6646 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6647 ((struct lys_feature *)item)->name);
6648 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006649 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006650 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006651 break;
6652 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006653 if (str_node) {
6654 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6655 } /* else no default value in the type itself, but we are checking some restrictions against
6656 * possible default value of some base type. The failure is caused by not resolved base type,
6657 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006658 break;
6659 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006660 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006661 break;
6662 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006663 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006664 break;
6665 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006666 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006667 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006668 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006669 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6670 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006671 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006672 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006673 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6674 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006675 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006676 case UNRES_EXT:
6677 extinfo = (struct unres_ext *)str_node;
6678 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6679 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6680 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006681 default:
6682 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006683 break;
6684 }
6685}
6686
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006687/**
Michal Vaskobb211122015-08-19 14:03:11 +02006688 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006689 *
6690 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006691 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006692 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006693 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006694 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006695int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006696resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006697{
Radek Krejci010e54b2016-03-15 09:40:34 +01006698 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006699 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006700
6701 assert(unres);
6702
Michal Vaskoe8734262016-09-29 14:12:06 +02006703 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006704 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006705
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006706 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006707 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006708 unres_count = 0;
6709 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006710
6711 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006712 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006713 * if-features are resolved here to make sure that we will have all if-features for
6714 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006715 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006716 continue;
6717 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006718 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006719 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006720
Michal Vasko88c29542015-11-27 14:57:53 +01006721 ++unres_count;
Michal Vasko769f8032017-01-24 13:11:55 +01006722 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006723 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006724 unres->type[i] = UNRES_RESOLVED;
6725 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006726 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006727 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006728 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006729 /* print the error */
Michal Vasko769f8032017-01-24 13:11:55 +01006730 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006731 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006732 } else {
6733 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006734 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006735 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006736 }
Michal Vasko88c29542015-11-27 14:57:53 +01006737 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006738
Michal Vasko88c29542015-11-27 14:57:53 +01006739 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006740 /* just print the errors */
6741 ly_vlog_hide(0);
6742
6743 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006744 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006745 continue;
6746 }
Michal Vasko769f8032017-01-24 13:11:55 +01006747 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006748 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006749 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006750 }
6751
Radek Krejci07d0fb92017-01-13 14:11:05 +01006752 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006753 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006754 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006755 continue;
6756 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006757
Michal Vasko769f8032017-01-24 13:11:55 +01006758 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006759 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006760 if (unres->type[i] == UNRES_LIST_UNIQ) {
6761 /* free the allocated structure */
6762 free(unres->item[i]);
6763 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006764 unres->type[i] = UNRES_RESOLVED;
6765 ++resolved;
6766 } else if (rc == -1) {
6767 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006768 /* print the error */
Michal Vasko769f8032017-01-24 13:11:55 +01006769 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006770 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006771 }
6772 }
6773
Radek Krejci010e54b2016-03-15 09:40:34 +01006774 ly_vlog_hide(0);
6775
Radek Krejci80056d52017-01-05 13:13:33 +01006776 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6777 for (i = 0; i < unres->count; ++i) {
6778 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6779 continue;
6780 }
6781
Radek Krejcicbba57c2017-01-24 13:43:20 +01006782 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006783 if (rc == 0) {
6784 unres->type[i] = UNRES_RESOLVED;
6785 ++resolved;
6786 }
6787 }
6788
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006789 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006790 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6791 * all the validation errors
6792 */
6793 for (i = 0; i < unres->count; ++i) {
6794 if (unres->type[i] == UNRES_RESOLVED) {
6795 continue;
6796 }
Michal Vasko769f8032017-01-24 13:11:55 +01006797 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006798 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006799 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006800 unres->type[i] = UNRES_RESOLVED;
6801 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006802 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006803 }
Radek Krejcib3142312016-11-09 11:04:12 +01006804 if (resolved < unres->count) {
6805 return -1;
6806 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006807 }
6808
Michal Vaskoe8734262016-09-29 14:12:06 +02006809 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006810 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006811 return EXIT_SUCCESS;
6812}
6813
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006814/**
Michal Vaskobb211122015-08-19 14:03:11 +02006815 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006816 *
6817 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006818 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006819 * @param[in] item Item to resolve. Type determined by \p type.
6820 * @param[in] type Type of the unresolved item.
6821 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006822 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006823 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006824 */
6825int
Radek Krejci48464ed2016-03-17 15:44:09 +01006826unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6827 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006828{
Radek Krejci54081ce2016-08-12 15:21:47 +02006829 int rc;
6830 const char *dictstr;
6831
6832 dictstr = lydict_insert(mod->ctx, str, 0);
6833 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6834
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006835 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006836 lydict_remove(mod->ctx, dictstr);
6837 }
6838 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006839}
6840
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006841/**
Michal Vaskobb211122015-08-19 14:03:11 +02006842 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006843 *
6844 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006845 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006846 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006847 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006848 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006849 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006850 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6851 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006852 */
6853int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006854unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006855 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006856{
Michal Vaskoef486d72016-09-27 12:10:44 +02006857 int rc, log_hidden;
Radek Krejci850a5de2016-11-08 14:06:40 +01006858 uint32_t u;
Michal Vasko88c29542015-11-27 14:57:53 +01006859 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006860
Michal Vasko9bf425b2015-10-22 11:42:03 +02006861 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6862 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006863
Radek Krejci850a5de2016-11-08 14:06:40 +01006864 /* check for duplicities in unres */
6865 for (u = 0; u < unres->count; u++) {
6866 if (unres->type[u] == type && unres->item[u] == item &&
6867 unres->str_snode[u] == snode && unres->module[u] == mod) {
6868 /* duplication, will be resolved later */
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006869 return -2;
Radek Krejci850a5de2016-11-08 14:06:40 +01006870 }
6871 }
6872
Radek Krejci80056d52017-01-05 13:13:33 +01006873 if (type != UNRES_EXT_FINALIZE) {
6874 /* extension finalization is not even tried when adding the item into the inres list */
Michal Vaskoef486d72016-09-27 12:10:44 +02006875
Radek Krejci80056d52017-01-05 13:13:33 +01006876 if (*ly_vlog_hide_location()) {
6877 log_hidden = 1;
6878 } else {
6879 log_hidden = 0;
6880 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006881 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006882 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006883 if (!log_hidden) {
6884 ly_vlog_hide(0);
6885 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006886
Radek Krejci80056d52017-01-05 13:13:33 +01006887 if (rc != EXIT_FAILURE) {
6888 if (rc == -1 && ly_errno == LY_EVALID) {
6889 ly_err_repeat();
6890 }
6891 if (type == UNRES_LIST_UNIQ) {
6892 /* free the allocated structure */
6893 free(item);
6894 } else if (rc == -1 && type == UNRES_IFFEAT) {
6895 /* free the allocated resources */
6896 free(*((char **)item));
6897 }
6898 return rc;
6899 } else {
6900 /* erase info about validation errors */
6901 ly_err_clean(1);
6902 }
Michal Vaskof02e3742015-08-05 16:27:02 +02006903
Radek Krejci80056d52017-01-05 13:13:33 +01006904 print_unres_schema_item_fail(item, type, snode);
6905
6906 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
6907 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
6908 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
6909 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6910 lyxml_unlink_elem(mod->ctx, yin, 1);
6911 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6912 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01006913 }
Michal Vasko88c29542015-11-27 14:57:53 +01006914 }
6915
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006916 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006917 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6918 if (!unres->item) {
6919 LOGMEM;
6920 return -1;
6921 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006922 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006923 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6924 if (!unres->type) {
6925 LOGMEM;
6926 return -1;
6927 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006928 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006929 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6930 if (!unres->str_snode) {
6931 LOGMEM;
6932 return -1;
6933 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006934 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006935 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6936 if (!unres->module) {
6937 LOGMEM;
6938 return -1;
6939 }
6940 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006941
Michal Vasko3767fb22016-07-21 12:10:57 +02006942 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006943}
6944
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006945/**
Michal Vaskobb211122015-08-19 14:03:11 +02006946 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006947 *
6948 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006949 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006950 * @param[in] item Old item to be resolved.
6951 * @param[in] type Type of the old unresolved item.
6952 * @param[in] new_item New item to use in the duplicate.
6953 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006954 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006955 */
Michal Vaskodad19402015-08-06 09:51:53 +02006956int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006957unres_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 +02006958{
6959 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006960 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006961 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006962
Michal Vaskocf024702015-10-08 15:01:42 +02006963 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006964
Radek Krejcid09d1a52016-08-11 14:05:45 +02006965 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6966 if (type == UNRES_LIST_UNIQ) {
6967 aux_uniq.list = item;
6968 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6969 item = &aux_uniq;
6970 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006971 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006972
6973 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006974 if (type == UNRES_LIST_UNIQ) {
6975 free(new_item);
6976 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006977 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006978 }
6979
Radek Krejcic79c6b12016-07-26 15:11:49 +02006980 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006981 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006982 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006983 LOGINT;
6984 return -1;
6985 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006986 } else if (type == UNRES_IFFEAT) {
6987 /* duplicate unres_iffeature_data */
6988 iff_data = malloc(sizeof *iff_data);
6989 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6990 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6991 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6992 LOGINT;
6993 return -1;
6994 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006995 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006996 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006997 LOGINT;
6998 return -1;
6999 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007000 }
Michal Vaskodad19402015-08-06 09:51:53 +02007001
7002 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007003}
7004
Michal Vaskof02e3742015-08-05 16:27:02 +02007005/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007006int
Michal Vasko878e38d2016-09-05 12:17:53 +02007007unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007008{
Michal Vasko878e38d2016-09-05 12:17:53 +02007009 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007010 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007011
Radek Krejciddddd0d2017-01-20 15:20:46 +01007012 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007013 i = start_on_backwards;
7014 } else {
7015 i = unres->count - 1;
7016 }
7017 for (; i > -1; i--) {
7018 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007019 continue;
7020 }
7021 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007022 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007023 break;
7024 }
7025 } else {
7026 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7027 aux_uniq2 = (struct unres_list_uniq *)item;
7028 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007029 break;
7030 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007031 }
7032 }
7033
Michal Vasko878e38d2016-09-05 12:17:53 +02007034 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007035}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007036
Michal Vaskoede9c472016-06-07 09:38:15 +02007037static void
7038unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7039{
7040 struct lyxml_elem *yin;
7041 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007042 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007043
7044 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007045 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007046 case UNRES_TYPE_DER:
7047 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7048 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7049 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007050 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007051 lydict_remove(ctx, yang->name);
7052 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007053 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7054 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7055 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007056 } else {
7057 lyxml_free(ctx, yin);
7058 }
7059 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007060 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007061 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7062 lydict_remove(ctx, iff_data->fname);
7063 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007064 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007065 case UNRES_IDENT:
7066 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007067 case UNRES_CHOICE_DFLT:
7068 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007069 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7070 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007071 case UNRES_LIST_UNIQ:
7072 free(unres->item[i]);
7073 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007074 default:
7075 break;
7076 }
7077 unres->type[i] = UNRES_RESOLVED;
7078}
7079
Michal Vasko88c29542015-11-27 14:57:53 +01007080void
Radek Krejcic071c542016-01-27 14:57:51 +01007081unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01007082{
7083 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007084 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007085
Radek Krejcic071c542016-01-27 14:57:51 +01007086 if (!unres || !(*unres)) {
7087 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007088 }
7089
Radek Krejcic071c542016-01-27 14:57:51 +01007090 assert(module || (*unres)->count == 0);
7091
7092 for (i = 0; i < (*unres)->count; ++i) {
7093 if ((*unres)->module[i] != module) {
7094 if ((*unres)->type[i] != UNRES_RESOLVED) {
7095 unresolved++;
7096 }
7097 continue;
7098 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007099
7100 /* free heap memory for the specific item */
7101 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007102 }
7103
Michal Vaskoede9c472016-06-07 09:38:15 +02007104 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01007105 if (!module || (!unresolved && !module->type)) {
7106 free((*unres)->item);
7107 free((*unres)->type);
7108 free((*unres)->str_snode);
7109 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007110 free((*unres));
7111 (*unres) = NULL;
7112 }
Michal Vasko88c29542015-11-27 14:57:53 +01007113}
7114
Michal Vasko3cfa3182017-01-17 10:00:58 +01007115static int
7116check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7117{
7118 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007119 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007120 char *buf;
7121
7122 for (op_node = lys_parent(sleaf);
7123 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7124 op_node = lys_parent(op_node));
7125
7126 if (op_node && lys_parent(op_node)) {
7127 /* nested operation - any absolute path is external */
7128 return 1;
7129 }
7130
7131 /* get the first node from the instid */
7132 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7133 if (!buf) {
7134 LOGMEM;
7135 return -1;
7136 }
7137
7138 /* there is a predicate, remove it */
7139 if (buf[strlen(buf) - 1] == ']') {
7140 assert(strchr(buf, '['));
7141 *strchr(buf, '[') = '\0';
7142 }
7143
7144 /* find the first schema node */
Michal Vasko2611e192017-01-23 10:33:21 +01007145 set = lys_find_xpath(NULL, sleaf, buf, 0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007146 if (!set || !set->number) {
7147 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007148 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007149 return 1;
7150 }
7151 free(buf);
7152
Michal Vasko3c777092017-01-17 14:10:09 +01007153 first_node = set->set.s[0];
7154 ly_set_free(set);
7155
Michal Vasko3cfa3182017-01-17 10:00:58 +01007156 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7157
7158 if (op_node) {
7159 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007160 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007161 assert(set->number == 1);
7162 return 0;
7163 } else {
7164 return 1;
7165 }
7166 }
7167
7168 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7169 * this itself), so we say it's not external */
7170 return 0;
7171}
7172
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007173/**
7174 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7175 *
7176 * @param[in] data Data node where the path is used
7177 * @param[in] path Instance-identifier node value.
7178 * @param[in,out] ret Resolved instance or NULL.
7179 *
7180 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7181 */
7182static int
7183resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7184{
7185 int i = 0, j;
7186 const struct lys_module *mod;
7187 struct ly_ctx *ctx = data->schema->module->ctx;
7188 const char *model, *name;
7189 char *str;
7190 int mod_len, name_len, has_predicate;
7191 struct unres_data node_match;
7192
7193 memset(&node_match, 0, sizeof node_match);
7194 *ret = NULL;
7195
7196 /* we need root to resolve absolute path */
7197 for (; data->parent; data = data->parent);
7198 /* we're still parsing it and the pointer is not correct yet */
7199 if (data->prev) {
7200 for (; data->prev->next; data = data->prev);
7201 }
7202
7203 /* search for the instance node */
7204 while (path[i]) {
7205 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7206 if (j <= 0) {
7207 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7208 goto error;
7209 }
7210 i += j;
7211
7212 str = strndup(model, mod_len);
7213 if (!str) {
7214 LOGMEM;
7215 goto error;
7216 }
7217 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007218 if (ctx->data_clb) {
7219 if (!mod) {
7220 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7221 } else if (!mod->implemented) {
7222 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7223 }
7224 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007225 free(str);
7226
Michal Vaskof53187d2017-01-13 13:23:14 +01007227 if (!mod || !mod->implemented || mod->disabled) {
7228 break;
7229 }
7230
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007231 if (resolve_data(mod, name, name_len, data, &node_match)) {
7232 /* no instance exists */
7233 break;
7234 }
7235
7236 if (has_predicate) {
7237 /* we have predicate, so the current results must be list or leaf-list */
7238 j = resolve_predicate(&path[i], &node_match);
7239 if (j < 1) {
7240 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7241 goto error;
7242 }
7243 i += j;
7244
7245 if (!node_match.count) {
7246 /* no instance exists */
7247 break;
7248 }
7249 }
7250 }
7251
7252 if (!node_match.count) {
7253 /* no instance exists */
7254 if (req_inst > -1) {
7255 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7256 return EXIT_FAILURE;
7257 }
7258 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7259 return EXIT_SUCCESS;
7260 } else if (node_match.count > 1) {
7261 /* instance identifier must resolve to a single node */
7262 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7263 goto error;
7264 } else {
7265 /* we have required result, remember it and cleanup */
7266 *ret = node_match.node[0];
7267 free(node_match.node);
7268 return EXIT_SUCCESS;
7269 }
7270
7271error:
7272 /* cleanup */
7273 free(node_match.node);
7274 return -1;
7275}
7276
7277static int
7278resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007279{
Radek Krejci7de36cf2016-09-12 16:18:50 +02007280 struct unres_data matches;
7281 uint32_t i;
7282
Radek Krejci9b6aad22016-09-20 15:55:51 +02007283 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007284 memset(&matches, 0, sizeof matches);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007285 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007286
7287 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007288 if (resolve_path_arg_data((struct lyd_node *)leaf, path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007289 return -1;
7290 }
7291
7292 /* check that value matches */
7293 for (i = 0; i < matches.count; ++i) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007294 /* not that the value is already in canonical form since the parsers does the conversion,
7295 * so we can simply compare just the values */
Radek Krejci7de36cf2016-09-12 16:18:50 +02007296 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007297 /* we have the match */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007298 *ret = matches.node[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007299 break;
7300 }
7301 }
7302
7303 free(matches.node);
7304
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007305 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007306 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007307 if (req_inst > -1) {
7308 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007309 return EXIT_FAILURE;
7310 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007311 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 +02007312 }
7313 }
7314
7315 return EXIT_SUCCESS;
7316}
7317
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007318/* 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 +01007319int
7320resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7321 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007322{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007323 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007324 struct lyd_node *ret;
7325 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007326 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007327
7328 assert(type->base == LY_TYPE_UNION);
7329
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007330 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7331 /* either NULL or instid previously converted to JSON */
7332 json_val = leaf->value.string;
7333 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007334
Michal Vaskofd6c6502017-01-06 12:15:41 +01007335 if (store) {
7336 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7337 free(leaf->value.bit);
7338 }
7339 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007340 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007341
7342 /* turn logging off, we are going to try to validate the value with all the types in order */
7343 hidden = *ly_vlog_hide_location();
7344 ly_vlog_hide(1);
7345
7346 t = NULL;
7347 found = 0;
7348 while ((t = lyp_get_next_union_type(type, t, &found))) {
7349 found = 0;
7350
7351 switch (t->base) {
7352 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007353 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7354 req_inst = -1;
7355 } else {
7356 req_inst = t->info.lref.req;
7357 }
7358
7359 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007360 if (store) {
7361 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7362 /* valid resolved */
7363 leaf->value.leafref = ret;
7364 leaf->value_type = LY_TYPE_LEAFREF;
7365 } else {
7366 /* valid unresolved */
7367 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, 1, 0)) {
7368 return -1;
7369 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007370 }
7371 }
7372
7373 success = 1;
7374 }
7375 break;
7376 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007377 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7378 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7379 req_inst = -1;
7380 } else {
7381 req_inst = t->info.inst.req;
7382 }
7383
Michal Vaskod3a03112017-01-23 09:56:02 +01007384 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007385 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007386 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007387 /* valid resolved */
7388 leaf->value.instance = ret;
7389 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007390
Michal Vaskofd6c6502017-01-06 12:15:41 +01007391 if (json_val) {
7392 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7393 leaf->value_str = json_val;
7394 json_val = NULL;
7395 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007396 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007397 /* valid unresolved */
7398 if (json_val) {
7399 /* put the JSON val back */
7400 leaf->value.string = json_val;
7401 json_val = NULL;
7402 } else {
7403 leaf->value.instance = NULL;
7404 }
7405 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007406 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007407 }
7408
7409 success = 1;
7410 }
7411 break;
7412 default:
Michal Vaskofd6c6502017-01-06 12:15:41 +01007413 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007414 success = 1;
7415 }
7416 break;
7417 }
7418
7419 if (success) {
7420 break;
7421 }
7422
7423 /* erase information about errors - they are false or irrelevant
7424 * and will be replaced by a single error messages */
7425 ly_err_clean(1);
7426
7427 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007428 if (store) {
7429 if (t->base == LY_TYPE_BITS) {
7430 free(leaf->value.bit);
7431 }
7432 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007433 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007434 }
7435
7436 /* turn logging back on */
7437 if (!hidden) {
7438 ly_vlog_hide(0);
7439 }
7440
7441 if (json_val) {
7442 if (!success) {
7443 /* put the value back for now */
7444 assert(leaf->value_type == LY_TYPE_UNION);
7445 leaf->value.string = json_val;
7446 } else {
7447 /* value was ultimately useless, but we could not have known */
7448 lydict_remove(leaf->schema->module->ctx, json_val);
7449 }
7450 }
7451
Michal Vaskofd6c6502017-01-06 12:15:41 +01007452 if (success) {
7453 if (resolved_type) {
7454 *resolved_type = t;
7455 }
7456 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007457 /* not found and it is required */
7458 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007459 return EXIT_FAILURE;
7460 }
7461
7462 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007463
Radek Krejci9b6aad22016-09-20 15:55:51 +02007464}
7465
Michal Vasko8bcdf292015-08-19 14:04:43 +02007466/**
7467 * @brief Resolve a single unres data item. Logs directly.
7468 *
Michal Vaskocf024702015-10-08 15:01:42 +02007469 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007470 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007471 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007472 *
7473 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7474 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007475int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007476resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007477{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007478 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007479 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007480 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007481 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007482
Michal Vasko83a6c462015-10-08 16:43:53 +02007483 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007484 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007485
Michal Vaskocf024702015-10-08 15:01:42 +02007486 switch (type) {
7487 case UNRES_LEAFREF:
7488 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007489 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007490 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7491 req_inst = -1;
7492 } else {
7493 req_inst = sleaf->type.info.lref.req;
7494 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007495 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7496 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007497 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007498 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007499 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7500 free(leaf->value.bit);
7501 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007502 leaf->value.leafref = ret;
7503 leaf->value_type = LY_TYPE_LEAFREF;
7504 } else {
7505 /* valid unresolved */
7506 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
7507 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, 1, 0)) {
7508 return -1;
7509 }
7510 }
7511 }
7512 leaf->validity &= ~LYD_VAL_LEAFREF;
7513 } else {
7514 return rc;
7515 }
7516 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007517
Michal Vaskocf024702015-10-08 15:01:42 +02007518 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007519 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007520 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7521 if (ext_dep == -1) {
7522 return -1;
7523 }
7524
7525 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7526 req_inst = -1;
7527 } else {
7528 req_inst = sleaf->type.info.inst.req;
7529 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007530 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7531 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007532 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007533 /* valid resolved */
7534 leaf->value.instance = ret;
7535 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007536 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007537 /* valid unresolved */
7538 leaf->value.instance = NULL;
7539 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007540 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007541 } else {
7542 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007543 }
Michal Vaskocf024702015-10-08 15:01:42 +02007544 break;
7545
Radek Krejci7de36cf2016-09-12 16:18:50 +02007546 case UNRES_UNION:
7547 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007548 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007549
Michal Vaskocf024702015-10-08 15:01:42 +02007550 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007551 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007552 return rc;
7553 }
7554 break;
7555
Michal Vaskobf19d252015-10-08 15:39:17 +02007556 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007557 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007558 return rc;
7559 }
7560 break;
7561
7562 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007563 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007564 return rc;
7565 }
7566 break;
7567
Michal Vaskocf024702015-10-08 15:01:42 +02007568 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007569 LOGINT;
7570 return -1;
7571 }
7572
7573 return EXIT_SUCCESS;
7574}
7575
7576/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007577 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007578 *
7579 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007580 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007581 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007582 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007583 */
7584int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007585unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007586{
Radek Krejci03b71f72016-03-16 11:10:09 +01007587 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007588 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007589 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007590
Radek Krejci03b71f72016-03-16 11:10:09 +01007591 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007592 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
7593 if (!unres->node) {
7594 LOGMEM;
7595 return -1;
7596 }
Michal Vaskocf024702015-10-08 15:01:42 +02007597 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007598 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
7599 if (!unres->type) {
7600 LOGMEM;
7601 return -1;
7602 }
Michal Vaskocf024702015-10-08 15:01:42 +02007603 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007604
Radek Krejci0b7704f2016-03-18 12:16:14 +01007605 if (type == UNRES_WHEN) {
7606 /* remove previous result */
7607 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007608 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007609
7610 return EXIT_SUCCESS;
7611}
7612
7613/**
7614 * @brief Resolve every unres data item in the structure. Logs directly.
7615 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007616 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7617 * unresolved leafrefs/instids are accepted).
7618 *
7619 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7620 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007621 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007622 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7623 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007624 *
7625 * @return EXIT_SUCCESS on success, -1 on error.
7626 */
7627int
Radek Krejci082c84f2016-10-17 16:33:06 +02007628resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007629{
Radek Krejci0c0086a2016-03-24 15:20:28 +01007630 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007631 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007632 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007633
Radek Krejci082c84f2016-10-17 16:33:06 +02007634 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007635 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007636
7637 if (!unres->count) {
7638 return EXIT_SUCCESS;
7639 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007640
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007641 if (options & (LYD_OPT_TRUSTED | LYD_OPT_NOTIF_FILTER | LYD_OPT_GET | LYD_OPT_GETCONFIG | LYD_OPT_EDIT)) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007642 ignore_fail = 1;
7643 } else if (options & LYD_OPT_NOEXTDEPS) {
7644 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007645 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007646 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007647 }
7648
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007649 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007650 ly_vlog_hide(1);
7651
Radek Krejci0b7704f2016-03-18 12:16:14 +01007652 /* when-stmt first */
Radek Krejci010e54b2016-03-15 09:40:34 +01007653 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007654 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007655 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007656 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007657 if (unres->type[i] != UNRES_WHEN) {
7658 continue;
7659 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007660 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007661 /* count when-stmt nodes in unres list */
7662 when_stmt++;
7663 }
7664
7665 /* resolve when condition only when all parent when conditions are already resolved */
7666 for (parent = unres->node[i]->parent;
7667 parent && LYD_WHEN_DONE(parent->when_status);
7668 parent = parent->parent) {
7669 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7670 /* the parent node was already unlinked, do not resolve this node,
7671 * it will be removed anyway, so just mark it as resolved
7672 */
7673 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7674 unres->type[i] = UNRES_RESOLVED;
7675 resolved++;
7676 break;
7677 }
7678 }
7679 if (parent) {
7680 continue;
7681 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007682
Michal Vasko3cfa3182017-01-17 10:00:58 +01007683 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007684 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007685 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007686 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007687 /* false when condition */
7688 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007689 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007690 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007691 } /* follows else */
7692
Radek Krejci0c0086a2016-03-24 15:20:28 +01007693 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7694 /* if it has parent non-presence containers that would be empty, we should actually
7695 * remove the container
7696 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007697 for (parent = unres->node[i];
7698 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7699 parent = parent->parent) {
7700 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7701 /* presence container */
7702 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007703 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007704 if (parent->next || parent->prev != parent) {
7705 /* non empty (the child we are in and we are going to remove is not the only child) */
7706 break;
7707 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007708 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007709 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007710
Radek Krejci0b7704f2016-03-18 12:16:14 +01007711 /* auto-delete */
7712 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7713 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01007714 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007715 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007716 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007717
Radek Krejci0b7704f2016-03-18 12:16:14 +01007718 lyd_unlink(unres->node[i]);
7719 unres->type[i] = UNRES_DELETE;
7720 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007721
7722 /* update the rest of unres items */
7723 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007724 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007725 continue;
7726 }
7727
7728 /* test if the node is in subtree to be deleted */
7729 for (parent = unres->node[j]; parent; parent = parent->parent) {
7730 if (parent == unres->node[i]) {
7731 /* yes, it is */
7732 unres->type[j] = UNRES_RESOLVED;
7733 resolved++;
7734 break;
7735 }
7736 }
7737 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007738 } else {
7739 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007740 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007741 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007742 resolved++;
7743 progress = 1;
7744 } else if (rc == -1) {
7745 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007746 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007747 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007748 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007749 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007750 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007751 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007752 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007753
Radek Krejci0b7704f2016-03-18 12:16:14 +01007754 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007755 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007756 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007757 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007758 return -1;
7759 }
7760
7761 for (i = 0; del_items && i < unres->count; i++) {
7762 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7763 if (unres->type[i] != UNRES_DELETE) {
7764 continue;
7765 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007766 if (!unres->node[i]) {
7767 unres->type[i] = UNRES_RESOLVED;
7768 del_items--;
7769 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007770 }
7771
7772 /* really remove the complete subtree */
7773 lyd_free(unres->node[i]);
7774 unres->type[i] = UNRES_RESOLVED;
7775 del_items--;
7776 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007777 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007778
7779 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007780 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007781 if (unres->type[i] == UNRES_RESOLVED) {
7782 continue;
7783 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007784 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007785
Michal Vasko3cfa3182017-01-17 10:00:58 +01007786 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007787 if (rc) {
7788 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007789 return -1;
7790 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007791
7792 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007793 }
7794
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007795 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007796 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007797 return EXIT_SUCCESS;
7798}