blob: 1fa73147d1eb1a99e868f82200cc18a35b13033d [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.
Michal Vasko50576712017-07-28 12:28:33 +0200158 * @param[out] all_desc Whether the path starts with '/', only supported in extended paths.
159 * @param[in] extended Whether to accept an extended path (support for [prefix:]*, /[prefix:]*, /[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200160 *
161 * @return Number of characters successfully parsed,
162 * positive on success, negative on failure.
163 */
164static int
Michal Vasko50576712017-07-28 12:28:33 +0200165parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
166 int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200167{
168 int parsed = 0, ret;
169
170 assert(id);
Michal Vasko50576712017-07-28 12:28:33 +0200171 assert((mod_name && mod_name_len) || (!mod_name && !mod_name_len));
172 assert((name && nam_len) || (!name && !nam_len));
173 assert(!extended || all_desc);
174
Michal Vasko723e50c2015-10-20 15:20:29 +0200175 if (mod_name) {
176 *mod_name = NULL;
Michal Vasko723e50c2015-10-20 15:20:29 +0200177 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200178 }
179 if (name) {
180 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200181 *nam_len = 0;
182 }
183
Michal Vasko50576712017-07-28 12:28:33 +0200184 if (extended) {
185 /* try to parse only the extended expressions */
186 if (id[parsed] == '/') {
187 *all_desc = 1;
188 } else {
189 *all_desc = 0;
190 }
191
192 /* is there a prefix? */
193 ret = parse_identifier(id + *all_desc);
194 if (ret > 0) {
195 if (id[*all_desc + ret] != ':') {
196 /* this is not a prefix, so not an extended id */
197 goto standard_id;
198 }
199
200 if (mod_name) {
201 *mod_name = id + *all_desc;
202 *mod_name_len = ret;
203 }
204
205 /* "/" and ":" */
206 ret += *all_desc + 1;
207 } else {
208 ret = *all_desc;
209 }
210
211 /* parse either "*" or "." */
212 if (!strcmp(id + ret, "*")) {
213 if (name) {
214 *name = id + ret;
215 *nam_len = 1;
216 }
217 ++ret;
218
219 return ret;
220 } else if (!strcmp(id + ret, ".")) {
221 if (!*all_desc) {
222 /* /. is redundant expression, we do not accept it */
223 return -ret;
224 }
225
226 if (name) {
227 *name = id + ret;
228 *nam_len = 1;
229 }
230 ++ret;
231
232 return ret;
233 }
234 /* else a standard id, parse it all again */
235 }
236
237standard_id:
Radek Krejci6dc53a22015-08-17 13:27:59 +0200238 if ((ret = parse_identifier(id)) < 1) {
239 return ret;
240 }
241
Michal Vasko723e50c2015-10-20 15:20:29 +0200242 if (mod_name) {
243 *mod_name = id;
Michal Vasko723e50c2015-10-20 15:20:29 +0200244 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200245 }
246
247 parsed += ret;
248 id += ret;
249
250 /* there is prefix */
251 if (id[0] == ':') {
252 ++parsed;
253 ++id;
254
255 /* there isn't */
256 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200257 if (name && mod_name) {
258 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200259 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200260 if (mod_name) {
261 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200262 }
263
Michal Vasko723e50c2015-10-20 15:20:29 +0200264 if (nam_len && mod_name_len) {
265 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200266 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200267 if (mod_name_len) {
268 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200269 }
270
271 return parsed;
272 }
273
274 /* identifier (node name) */
275 if ((ret = parse_identifier(id)) < 1) {
276 return -parsed+ret;
277 }
278
279 if (name) {
280 *name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200281 *nam_len = ret;
282 }
283
284 return parsed+ret;
285}
286
287/**
288 * @brief Parse a path-predicate (leafref).
289 *
290 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
291 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
292 *
Michal Vaskobb211122015-08-19 14:03:11 +0200293 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200294 * @param[out] prefix Points to the prefix, NULL if there is not any.
295 * @param[out] pref_len Length of the prefix, 0 if there is not any.
296 * @param[out] name Points to the node name.
297 * @param[out] nam_len Length of the node name.
298 * @param[out] path_key_expr Points to the path-key-expr.
299 * @param[out] pke_len Length of the path-key-expr.
300 * @param[out] has_predicate Flag to mark whether there is another predicate following.
301 *
302 * @return Number of characters successfully parsed,
303 * positive on success, negative on failure.
304 */
305static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200306parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
307 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200308{
309 const char *ptr;
310 int parsed = 0, ret;
311
312 assert(id);
313 if (prefix) {
314 *prefix = NULL;
315 }
316 if (pref_len) {
317 *pref_len = 0;
318 }
319 if (name) {
320 *name = NULL;
321 }
322 if (nam_len) {
323 *nam_len = 0;
324 }
325 if (path_key_expr) {
326 *path_key_expr = NULL;
327 }
328 if (pke_len) {
329 *pke_len = 0;
330 }
331 if (has_predicate) {
332 *has_predicate = 0;
333 }
334
335 if (id[0] != '[') {
336 return -parsed;
337 }
338
339 ++parsed;
340 ++id;
341
342 while (isspace(id[0])) {
343 ++parsed;
344 ++id;
345 }
346
Michal Vasko50576712017-07-28 12:28:33 +0200347 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200348 return -parsed+ret;
349 }
350
351 parsed += ret;
352 id += ret;
353
354 while (isspace(id[0])) {
355 ++parsed;
356 ++id;
357 }
358
359 if (id[0] != '=') {
360 return -parsed;
361 }
362
363 ++parsed;
364 ++id;
365
366 while (isspace(id[0])) {
367 ++parsed;
368 ++id;
369 }
370
371 if ((ptr = strchr(id, ']')) == NULL) {
372 return -parsed;
373 }
374
375 --ptr;
376 while (isspace(ptr[0])) {
377 --ptr;
378 }
379 ++ptr;
380
381 ret = ptr-id;
382 if (path_key_expr) {
383 *path_key_expr = id;
384 }
385 if (pke_len) {
386 *pke_len = ret;
387 }
388
389 parsed += ret;
390 id += ret;
391
392 while (isspace(id[0])) {
393 ++parsed;
394 ++id;
395 }
396
397 assert(id[0] == ']');
398
399 if (id[1] == '[') {
400 *has_predicate = 1;
401 }
402
403 return parsed+1;
404}
405
406/**
407 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
408 * the ".." and the first node-identifier, other calls parse a single
409 * node-identifier each.
410 *
411 * path-key-expr = current-function-invocation *WSP "/" *WSP
412 * rel-path-keyexpr
413 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
414 * *(node-identifier *WSP "/" *WSP)
415 * node-identifier
416 *
Michal Vaskobb211122015-08-19 14:03:11 +0200417 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200418 * @param[out] prefix Points to the prefix, NULL if there is not any.
419 * @param[out] pref_len Length of the prefix, 0 if there is not any.
420 * @param[out] name Points to the node name.
421 * @param[out] nam_len Length of the node name.
422 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
423 * must not be changed between consecutive calls.
424 * @return Number of characters successfully parsed,
425 * positive on success, negative on failure.
426 */
427static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200428parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
429 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200430{
431 int parsed = 0, ret, par_times = 0;
432
433 assert(id);
434 assert(parent_times);
435 if (prefix) {
436 *prefix = NULL;
437 }
438 if (pref_len) {
439 *pref_len = 0;
440 }
441 if (name) {
442 *name = NULL;
443 }
444 if (nam_len) {
445 *nam_len = 0;
446 }
447
448 if (!*parent_times) {
449 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
450 if (strncmp(id, "current()", 9)) {
451 return -parsed;
452 }
453
454 parsed += 9;
455 id += 9;
456
457 while (isspace(id[0])) {
458 ++parsed;
459 ++id;
460 }
461
462 if (id[0] != '/') {
463 return -parsed;
464 }
465
466 ++parsed;
467 ++id;
468
469 while (isspace(id[0])) {
470 ++parsed;
471 ++id;
472 }
473
474 /* rel-path-keyexpr */
475 if (strncmp(id, "..", 2)) {
476 return -parsed;
477 }
478 ++par_times;
479
480 parsed += 2;
481 id += 2;
482
483 while (isspace(id[0])) {
484 ++parsed;
485 ++id;
486 }
487 }
488
489 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
490 *
491 * first parent reference with whitespaces already parsed
492 */
493 if (id[0] != '/') {
494 return -parsed;
495 }
496
497 ++parsed;
498 ++id;
499
500 while (isspace(id[0])) {
501 ++parsed;
502 ++id;
503 }
504
505 while (!strncmp(id, "..", 2) && !*parent_times) {
506 ++par_times;
507
508 parsed += 2;
509 id += 2;
510
511 while (isspace(id[0])) {
512 ++parsed;
513 ++id;
514 }
515
516 if (id[0] != '/') {
517 return -parsed;
518 }
519
520 ++parsed;
521 ++id;
522
523 while (isspace(id[0])) {
524 ++parsed;
525 ++id;
526 }
527 }
528
529 if (!*parent_times) {
530 *parent_times = par_times;
531 }
532
533 /* all parent references must be parsed at this point */
Michal Vasko50576712017-07-28 12:28:33 +0200534 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
535 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200536 }
537
538 parsed += ret;
539 id += ret;
540
541 return parsed;
542}
543
544/**
545 * @brief Parse path-arg (leafref).
546 *
547 * path-arg = absolute-path / relative-path
548 * absolute-path = 1*("/" (node-identifier *path-predicate))
549 * relative-path = 1*(".." "/") descendant-path
550 *
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200551 * @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 +0200552 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200553 * @param[out] prefix Points to the prefix, NULL if there is not any.
554 * @param[out] pref_len Length of the prefix, 0 if there is not any.
555 * @param[out] name Points to the node name.
556 * @param[out] nam_len Length of the node name.
557 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
558 * must not be changed between consecutive calls. -1 if the
559 * path is relative.
560 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
561 *
562 * @return Number of characters successfully parsed,
563 * positive on success, negative on failure.
564 */
565static int
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200566parse_path_arg(const struct lys_module *mod, const char *id, const char **prefix, int *pref_len,
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200567 const char **name, int *nam_len, int *parent_times, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200568{
569 int parsed = 0, ret, par_times = 0;
570
571 assert(id);
572 assert(parent_times);
573 if (prefix) {
574 *prefix = NULL;
575 }
576 if (pref_len) {
577 *pref_len = 0;
578 }
579 if (name) {
580 *name = NULL;
581 }
582 if (nam_len) {
583 *nam_len = 0;
584 }
585 if (has_predicate) {
586 *has_predicate = 0;
587 }
588
589 if (!*parent_times && !strncmp(id, "..", 2)) {
590 ++par_times;
591
592 parsed += 2;
593 id += 2;
594
595 while (!strncmp(id, "/..", 3)) {
596 ++par_times;
597
598 parsed += 3;
599 id += 3;
600 }
601 }
602
603 if (!*parent_times) {
604 if (par_times) {
605 *parent_times = par_times;
606 } else {
607 *parent_times = -1;
608 }
609 }
610
611 if (id[0] != '/') {
612 return -parsed;
613 }
614
615 /* skip '/' */
616 ++parsed;
617 ++id;
618
619 /* node-identifier ([prefix:]identifier) */
Michal Vasko50576712017-07-28 12:28:33 +0200620 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len, NULL, 0)) < 1) {
621 return -parsed - ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200622 }
Michal Vasko3c60cbb2017-07-10 11:50:03 +0200623 if (prefix && !(*prefix)) {
Radek Krejcif7ed4c32016-10-27 16:20:03 +0200624 /* actually we always need prefix even it is not specified */
625 *prefix = lys_main_module(mod)->name;
626 *pref_len = strlen(*prefix);
627 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200628
629 parsed += ret;
630 id += ret;
631
632 /* there is no predicate */
633 if ((id[0] == '/') || !id[0]) {
634 return parsed;
635 } else if (id[0] != '[') {
636 return -parsed;
637 }
638
639 if (has_predicate) {
640 *has_predicate = 1;
641 }
642
643 return parsed;
644}
645
646/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200647 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vasko1b6ca962017-08-03 14:23:09 +0200648 * are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200649 *
650 * instance-identifier = 1*("/" (node-identifier *predicate))
651 *
Michal Vaskobb211122015-08-19 14:03:11 +0200652 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200653 * @param[out] model Points to the model name.
654 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200655 * @param[out] name Points to the node name.
656 * @param[out] nam_len Length of the node name.
657 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
658 *
659 * @return Number of characters successfully parsed,
660 * positive on success, negative on failure.
661 */
662static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200663parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
664 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200665{
666 int parsed = 0, ret;
667
Michal Vasko1b6ca962017-08-03 14:23:09 +0200668 assert(id && model && mod_len && name && nam_len);
669
Radek Krejci6dc53a22015-08-17 13:27:59 +0200670 if (has_predicate) {
671 *has_predicate = 0;
672 }
673
674 if (id[0] != '/') {
675 return -parsed;
676 }
677
678 ++parsed;
679 ++id;
680
Michal Vaskob2f40be2016-09-08 16:03:48 +0200681 if ((ret = parse_identifier(id)) < 1) {
682 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200683 }
684
Michal Vaskob2f40be2016-09-08 16:03:48 +0200685 *name = id;
686 *nam_len = ret;
687
688 parsed += ret;
689 id += ret;
690
Michal Vasko1b6ca962017-08-03 14:23:09 +0200691 if (id[0] == ':') {
692 /* we have prefix */
693 *model = *name;
694 *mod_len = *nam_len;
695
696 ++parsed;
697 ++id;
698
699 if ((ret = parse_identifier(id)) < 1) {
700 return ret;
701 }
702
703 *name = id;
704 *nam_len = ret;
705
706 parsed += ret;
707 id += ret;
708 }
709
Radek Krejci4967cb62016-09-14 16:40:28 +0200710 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200711 *has_predicate = 1;
712 }
713
714 return parsed;
715}
716
717/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200718 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200719 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200720 *
721 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
722 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
723 * ((DQUOTE string DQUOTE) /
724 * (SQUOTE string SQUOTE))
725 * pos = non-negative-integer-value
726 *
Michal Vaskobb211122015-08-19 14:03:11 +0200727 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200728 * @param[out] model Points to the model name.
729 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200730 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
731 * @param[out] nam_len Length of the node name.
732 * @param[out] value Value the node-identifier must have (string from the grammar),
733 * NULL if there is not any.
734 * @param[out] val_len Length of the value, 0 if there is not any.
735 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
736 *
737 * @return Number of characters successfully parsed,
738 * positive on success, negative on failure.
739 */
740static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200741parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
742 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200743{
744 const char *ptr;
745 int parsed = 0, ret;
746 char quote;
747
748 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200749 if (model) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200750 assert(mod_len);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200751 *model = NULL;
Michal Vasko1f2cc332015-08-19 11:18:32 +0200752 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200753 }
754 if (name) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200755 assert(nam_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200756 *name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200757 *nam_len = 0;
758 }
759 if (value) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200760 assert(val_len);
Radek Krejci6dc53a22015-08-17 13:27:59 +0200761 *value = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200762 *val_len = 0;
763 }
764 if (has_predicate) {
765 *has_predicate = 0;
766 }
767
768 if (id[0] != '[') {
769 return -parsed;
770 }
771
772 ++parsed;
773 ++id;
774
775 while (isspace(id[0])) {
776 ++parsed;
777 ++id;
778 }
779
780 /* pos */
781 if (isdigit(id[0])) {
782 if (name) {
783 *name = id;
784 }
785
786 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200787 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200788 }
789
790 while (isdigit(id[0])) {
791 ++parsed;
792 ++id;
793 }
794
795 if (nam_len) {
796 *nam_len = id-(*name);
797 }
798
Michal Vaskof2f28a12016-09-09 12:43:06 +0200799 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200800 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200801 if (id[0] == '.') {
802 if (name) {
803 *name = id;
804 }
805 if (nam_len) {
806 *nam_len = 1;
807 }
808
809 ++parsed;
810 ++id;
811
812 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200813 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko1b6ca962017-08-03 14:23:09 +0200814 return -parsed + ret;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200815 }
816
817 parsed += ret;
818 id += ret;
819 }
820
821 while (isspace(id[0])) {
822 ++parsed;
823 ++id;
824 }
825
826 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200827 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200828 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200829
Radek Krejci6dc53a22015-08-17 13:27:59 +0200830 ++parsed;
831 ++id;
832
Michal Vaskof2f28a12016-09-09 12:43:06 +0200833 while (isspace(id[0])) {
834 ++parsed;
835 ++id;
836 }
837
838 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
839 if ((id[0] == '\"') || (id[0] == '\'')) {
840 quote = id[0];
841
842 ++parsed;
843 ++id;
844
845 if ((ptr = strchr(id, quote)) == NULL) {
846 return -parsed;
847 }
Michal Vasko1b6ca962017-08-03 14:23:09 +0200848 ret = ptr - id;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200849
850 if (value) {
851 *value = id;
852 }
853 if (val_len) {
854 *val_len = ret;
855 }
856
Michal Vasko1b6ca962017-08-03 14:23:09 +0200857 parsed += ret + 1;
858 id += ret + 1;
Michal Vaskof2f28a12016-09-09 12:43:06 +0200859 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200860 return -parsed;
861 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200862 }
863
864 while (isspace(id[0])) {
865 ++parsed;
866 ++id;
867 }
868
869 if (id[0] != ']') {
870 return -parsed;
871 }
872
873 ++parsed;
874 ++id;
875
876 if ((id[0] == '[') && has_predicate) {
877 *has_predicate = 1;
878 }
879
880 return parsed;
881}
882
883/**
884 * @brief Parse schema-nodeid.
885 *
886 * schema-nodeid = absolute-schema-nodeid /
887 * descendant-schema-nodeid
888 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200889 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200890 * node-identifier
891 * absolute-schema-nodeid
892 *
Michal Vaskobb211122015-08-19 14:03:11 +0200893 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200894 * @param[out] mod_name Points to the module name, NULL if there is not any.
895 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200896 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200897 * @param[out] nam_len Length of the node name.
898 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
899 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100900 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
901 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200902 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200903 *
904 * @return Number of characters successfully parsed,
905 * positive on success, negative on failure.
906 */
Michal Vasko22448d32016-03-16 13:17:29 +0100907int
Michal Vasko723e50c2015-10-20 15:20:29 +0200908parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko50576712017-07-28 12:28:33 +0200909 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200910{
911 int parsed = 0, ret;
912
913 assert(id);
914 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200915
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100916 if (has_predicate) {
917 *has_predicate = 0;
918 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200919
920 if (id[0] != '/') {
921 if (*is_relative != -1) {
922 return -parsed;
923 } else {
924 *is_relative = 1;
925 }
Michal Vasko48935352016-03-29 11:52:36 +0200926 if (!strncmp(id, "./", 2)) {
927 parsed += 2;
928 id += 2;
929 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200930 } else {
931 if (*is_relative == -1) {
932 *is_relative = 0;
933 }
934 ++parsed;
935 ++id;
936 }
937
Michal Vasko50576712017-07-28 12:28:33 +0200938 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
939 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200940 }
941
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100942 parsed += ret;
943 id += ret;
944
945 if ((id[0] == '[') && has_predicate) {
946 *has_predicate = 1;
947 }
948
949 return parsed;
950}
951
952/**
953 * @brief Parse schema predicate (special format internally used).
954 *
955 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vaskof359b022017-07-04 13:50:04 +0200956 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100957 * key-with-value = identifier *WSP "=" *WSP
958 * ((DQUOTE string DQUOTE) /
959 * (SQUOTE string SQUOTE))
960 *
961 * @param[in] id Identifier to use.
Michal Vaskof359b022017-07-04 13:50:04 +0200962 * @param[out] mod_name Points to the list key module name.
963 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100964 * @param[out] name Points to the list key name.
965 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100966 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100967 * @param[out] val_len Length of \p value.
968 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
969 */
Michal Vasko22448d32016-03-16 13:17:29 +0100970int
Michal Vaskof359b022017-07-04 13:50:04 +0200971parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
972 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100973{
974 const char *ptr;
975 int parsed = 0, ret;
976 char quote;
977
978 assert(id);
Michal Vaskof359b022017-07-04 13:50:04 +0200979 if (mod_name) {
980 *mod_name = NULL;
981 }
982 if (mod_name_len) {
983 *mod_name_len = 0;
984 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100985 if (name) {
986 *name = NULL;
987 }
988 if (nam_len) {
989 *nam_len = 0;
990 }
991 if (value) {
992 *value = NULL;
993 }
994 if (val_len) {
995 *val_len = 0;
996 }
997 if (has_predicate) {
998 *has_predicate = 0;
999 }
1000
1001 if (id[0] != '[') {
1002 return -parsed;
1003 }
1004
1005 ++parsed;
1006 ++id;
1007
1008 while (isspace(id[0])) {
1009 ++parsed;
1010 ++id;
1011 }
1012
Michal Vasko22448d32016-03-16 13:17:29 +01001013 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001014 if (id[0] == '.') {
1015 ret = 1;
Michal Vaskof359b022017-07-04 13:50:04 +02001016
1017 if (name) {
1018 *name = id;
1019 }
1020 if (nam_len) {
1021 *nam_len = ret;
1022 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001023 } else if (isdigit(id[0])) {
1024 if (id[0] == '0') {
1025 return -parsed;
1026 }
1027 ret = 1;
1028 while (isdigit(id[ret])) {
1029 ++ret;
1030 }
Michal Vaskof359b022017-07-04 13:50:04 +02001031
1032 if (name) {
1033 *name = id;
1034 }
1035 if (nam_len) {
1036 *nam_len = ret;
1037 }
Michal Vasko50576712017-07-28 12:28:33 +02001038 } else if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, NULL, 0)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001039 return -parsed + ret;
1040 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001041
1042 parsed += ret;
1043 id += ret;
1044
1045 while (isspace(id[0])) {
1046 ++parsed;
1047 ++id;
1048 }
1049
1050 /* there is value as well */
1051 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001052 if (name && isdigit(**name)) {
1053 return -parsed;
1054 }
1055
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001056 ++parsed;
1057 ++id;
1058
1059 while (isspace(id[0])) {
1060 ++parsed;
1061 ++id;
1062 }
1063
1064 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1065 if ((id[0] == '\"') || (id[0] == '\'')) {
1066 quote = id[0];
1067
1068 ++parsed;
1069 ++id;
1070
1071 if ((ptr = strchr(id, quote)) == NULL) {
1072 return -parsed;
1073 }
1074 ret = ptr - id;
1075
1076 if (value) {
1077 *value = id;
1078 }
1079 if (val_len) {
1080 *val_len = ret;
1081 }
1082
1083 parsed += ret + 1;
1084 id += ret + 1;
1085 } else {
1086 return -parsed;
1087 }
1088
1089 while (isspace(id[0])) {
1090 ++parsed;
1091 ++id;
1092 }
1093 }
1094
1095 if (id[0] != ']') {
1096 return -parsed;
1097 }
1098
1099 ++parsed;
1100 ++id;
1101
1102 if ((id[0] == '[') && has_predicate) {
1103 *has_predicate = 1;
1104 }
1105
1106 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001107}
1108
1109/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001110 * @brief Resolve (find) a feature definition. Logs directly.
1111 *
1112 * @param[in] feat_name Feature name to resolve.
1113 * @param[in] len Length of \p feat_name.
1114 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001115 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1116 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001118 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001119 */
1120static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001121resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001122{
1123 char *str;
1124 const char *mod_name, *name;
1125 int mod_name_len, nam_len, i, j;
1126 const struct lys_module *module;
1127
Radek Krejci9ff0a922016-07-14 13:08:05 +02001128 assert(feature);
1129
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001130 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001131 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0)) < 1) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001132 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1133 return -1;
1134 }
1135
1136 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1137 if (!module) {
1138 /* identity refers unknown data model */
1139 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1140 return -1;
1141 }
1142
Radek Krejci9ff0a922016-07-14 13:08:05 +02001143 if (module != node->module && module == lys_node_module(node)) {
1144 /* first, try to search directly in submodule where the feature was mentioned */
1145 for (j = 0; j < node->module->features_size; j++) {
1146 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1147 /* check status */
1148 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001149 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001150 return -1;
1151 }
1152 *feature = &node->module->features[j];
1153 return 0;
1154 }
1155 }
1156 }
1157
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001158 /* search in the identified module ... */
1159 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001160 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001161 /* check status */
1162 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001163 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001164 return -1;
1165 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001166 *feature = &module->features[j];
1167 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001168 }
1169 }
1170 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001171 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001172 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001173 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1174 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001175 /* check status */
1176 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1177 module->inc[i].submodule->features[j].flags,
1178 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001179 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001180 return -1;
1181 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001182 *feature = &module->inc[i].submodule->features[j];
1183 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001184 }
1185 }
1186 }
1187
1188 /* not found */
1189 str = strndup(feat_name, len);
1190 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1191 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001192 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001193}
1194
Radek Krejci9ff0a922016-07-14 13:08:05 +02001195/*
1196 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001197 * - 1 if enabled
1198 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001199 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001200static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001201resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001202{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001203 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001204
Radek Krejci9ff0a922016-07-14 13:08:05 +02001205 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001206 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001207 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001208 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001209 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001210
Radek Krejci69b8d922016-07-27 13:13:41 +02001211 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001212}
1213
1214static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001215resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001216{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001217 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001218 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001219
Radek Krejci9ff0a922016-07-14 13:08:05 +02001220 op = iff_getop(expr->expr, *index_e);
1221 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001222
Radek Krejci9ff0a922016-07-14 13:08:05 +02001223 switch (op) {
1224 case LYS_IFF_F:
1225 /* resolve feature */
1226 return resolve_feature_value(expr->features[(*index_f)++]);
1227 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001228 /* invert result */
1229 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001230 case LYS_IFF_AND:
1231 case LYS_IFF_OR:
1232 a = resolve_iffeature_recursive(expr, index_e, index_f);
1233 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001234 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001235 return a && b;
1236 } else { /* LYS_IFF_OR */
1237 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001238 }
1239 }
1240
Radek Krejciaf566332017-02-07 15:56:59 +01001241 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001242}
1243
1244int
1245resolve_iffeature(struct lys_iffeature *expr)
1246{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001247 int index_e = 0, index_f = 0;
1248
1249 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001250 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001251 }
Radek Krejciaf566332017-02-07 15:56:59 +01001252 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001253}
1254
1255struct iff_stack {
1256 int size;
1257 int index; /* first empty item */
1258 uint8_t *stack;
1259};
1260
1261static int
1262iff_stack_push(struct iff_stack *stack, uint8_t value)
1263{
1264 if (stack->index == stack->size) {
1265 stack->size += 4;
1266 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001267 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM; stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001268 }
1269
1270 stack->stack[stack->index++] = value;
1271 return EXIT_SUCCESS;
1272}
1273
1274static uint8_t
1275iff_stack_pop(struct iff_stack *stack)
1276{
1277 stack->index--;
1278 return stack->stack[stack->index];
1279}
1280
1281static void
1282iff_stack_clean(struct iff_stack *stack)
1283{
1284 stack->size = 0;
1285 free(stack->stack);
1286}
1287
1288static void
1289iff_setop(uint8_t *list, uint8_t op, int pos)
1290{
1291 uint8_t *item;
1292 uint8_t mask = 3;
1293
1294 assert(pos >= 0);
1295 assert(op <= 3); /* max 2 bits */
1296
1297 item = &list[pos / 4];
1298 mask = mask << 2 * (pos % 4);
1299 *item = (*item) & ~mask;
1300 *item = (*item) | (op << 2 * (pos % 4));
1301}
1302
1303uint8_t
1304iff_getop(uint8_t *list, int pos)
1305{
1306 uint8_t *item;
1307 uint8_t mask = 3, result;
1308
1309 assert(pos >= 0);
1310
1311 item = &list[pos / 4];
1312 result = (*item) & (mask << 2 * (pos % 4));
1313 return result >> 2 * (pos % 4);
1314}
1315
1316#define LYS_IFF_LP 0x04 /* ( */
1317#define LYS_IFF_RP 0x08 /* ) */
1318
Radek Krejcicbb473e2016-09-16 14:48:32 +02001319/* internal structure for passing data for UNRES_IFFEAT */
1320struct unres_iffeat_data {
1321 struct lys_node *node;
1322 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001323 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001324};
1325
Radek Krejci9ff0a922016-07-14 13:08:05 +02001326void
1327resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1328{
1329 unsigned int e = 0, f = 0, r = 0;
1330 uint8_t op;
1331
1332 assert(iffeat);
1333
1334 if (!iffeat->expr) {
1335 goto result;
1336 }
1337
1338 do {
1339 op = iff_getop(iffeat->expr, e++);
1340 switch (op) {
1341 case LYS_IFF_NOT:
1342 if (!r) {
1343 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001344 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001345 break;
1346 case LYS_IFF_AND:
1347 case LYS_IFF_OR:
1348 if (!r) {
1349 r += 2;
1350 } else {
1351 r += 1;
1352 }
1353 break;
1354 case LYS_IFF_F:
1355 f++;
1356 if (r) {
1357 r--;
1358 }
1359 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001360 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001361 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001362
Radek Krejci9ff0a922016-07-14 13:08:05 +02001363result:
1364 if (expr_size) {
1365 *expr_size = e;
1366 }
1367 if (feat_size) {
1368 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001369 }
1370}
1371
1372int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001373resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001374 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001375{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001376 const char *c = value;
1377 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001378 int i, j, last_not, checkversion = 0;
1379 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001380 uint8_t op;
1381 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001382 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001383
Radek Krejci9ff0a922016-07-14 13:08:05 +02001384 assert(c);
1385
1386 if (isspace(c[0])) {
1387 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1388 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001389 }
1390
Radek Krejci9ff0a922016-07-14 13:08:05 +02001391 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1392 for (i = j = last_not = 0; c[i]; i++) {
1393 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001394 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001395 j++;
1396 continue;
1397 } else if (c[i] == ')') {
1398 j--;
1399 continue;
1400 } else if (isspace(c[i])) {
1401 continue;
1402 }
1403
1404 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1405 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001406 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001407 return EXIT_FAILURE;
1408 } else if (!isspace(c[i + r])) {
1409 /* feature name starting with the not/and/or */
1410 last_not = 0;
1411 f_size++;
1412 } else if (c[i] == 'n') { /* not operation */
1413 if (last_not) {
1414 /* double not */
1415 expr_size = expr_size - 2;
1416 last_not = 0;
1417 } else {
1418 last_not = 1;
1419 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001420 } else { /* and, or */
1421 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001422 /* not a not operation */
1423 last_not = 0;
1424 }
1425 i += r;
1426 } else {
1427 f_size++;
1428 last_not = 0;
1429 }
1430 expr_size++;
1431
1432 while (!isspace(c[i])) {
1433 if (!c[i] || c[i] == ')') {
1434 i--;
1435 break;
1436 }
1437 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001438 }
1439 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001440 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001441 /* not matching count of ( and ) */
1442 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1443 return EXIT_FAILURE;
1444 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001445
Radek Krejci69b8d922016-07-27 13:13:41 +02001446 if (checkversion || expr_size > 1) {
1447 /* check that we have 1.1 module */
1448 if (node->module->version != 2) {
1449 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1450 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1451 return EXIT_FAILURE;
1452 }
1453 }
1454
Radek Krejci9ff0a922016-07-14 13:08:05 +02001455 /* allocate the memory */
1456 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001457 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001458 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001459 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM, error);
1460 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001461 f_size--; expr_size--; /* used as indexes from now */
1462
1463 for (i--; i >= 0; i--) {
1464 if (c[i] == ')') {
1465 /* push it on stack */
1466 iff_stack_push(&stack, LYS_IFF_RP);
1467 continue;
1468 } else if (c[i] == '(') {
1469 /* pop from the stack into result all operators until ) */
1470 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1471 iff_setop(iffeat_expr->expr, op, expr_size--);
1472 }
1473 continue;
1474 } else if (isspace(c[i])) {
1475 continue;
1476 }
1477
1478 /* end operator or operand -> find beginning and get what is it */
1479 j = i + 1;
1480 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1481 i--;
1482 }
1483 i++; /* get back by one step */
1484
1485 if (!strncmp(&c[i], "not ", 4)) {
1486 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1487 /* double not */
1488 iff_stack_pop(&stack);
1489 } else {
1490 /* not has the highest priority, so do not pop from the stack
1491 * as in case of AND and OR */
1492 iff_stack_push(&stack, LYS_IFF_NOT);
1493 }
1494 } else if (!strncmp(&c[i], "and ", 4)) {
1495 /* as for OR - pop from the stack all operators with the same or higher
1496 * priority and store them to the result, then push the AND to the stack */
1497 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1498 op = iff_stack_pop(&stack);
1499 iff_setop(iffeat_expr->expr, op, expr_size--);
1500 }
1501 iff_stack_push(&stack, LYS_IFF_AND);
1502 } else if (!strncmp(&c[i], "or ", 3)) {
1503 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1504 op = iff_stack_pop(&stack);
1505 iff_setop(iffeat_expr->expr, op, expr_size--);
1506 }
1507 iff_stack_push(&stack, LYS_IFF_OR);
1508 } else {
1509 /* feature name, length is j - i */
1510
1511 /* add it to the result */
1512 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1513
1514 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001515 * forward referenced, we have to keep the feature name in auxiliary
1516 * structure passed into unres */
1517 iff_data = malloc(sizeof *iff_data);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001518 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM, error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001519 iff_data->node = node;
1520 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001521 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001522 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1523 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001524 f_size--;
1525
1526 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001527 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001528 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001529 }
1530 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001531 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001532 while (stack.index) {
1533 op = iff_stack_pop(&stack);
1534 iff_setop(iffeat_expr->expr, op, expr_size--);
1535 }
1536
1537 if (++expr_size || ++f_size) {
1538 /* not all expected operators and operands found */
1539 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1540 rc = EXIT_FAILURE;
1541 } else {
1542 rc = EXIT_SUCCESS;
1543 }
1544
1545error:
1546 /* cleanup */
1547 iff_stack_clean(&stack);
1548
1549 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001550}
1551
1552/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001553 * @brief Resolve (find) a data node based on a schema-nodeid.
1554 *
1555 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1556 * module).
1557 *
1558 */
1559struct lyd_node *
1560resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1561{
1562 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001563 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001564 const struct lys_node *schema = NULL;
1565
1566 assert(nodeid && start);
1567
1568 if (nodeid[0] == '/') {
1569 return NULL;
1570 }
1571
1572 str = p = strdup(nodeid);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001573 LY_CHECK_ERR_RETURN(!str, LOGMEM, NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001574
Michal Vasko3edeaf72016-02-11 13:17:43 +01001575 while (p) {
1576 token = p;
1577 p = strchr(p, '/');
1578 if (p) {
1579 *p = '\0';
1580 p++;
1581 }
1582
Radek Krejci5da4eb62016-04-08 14:45:51 +02001583 if (p) {
1584 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001585 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001586 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001587 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001588 result = NULL;
1589 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001590 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001591
Radek Krejci5da4eb62016-04-08 14:45:51 +02001592 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1593 continue;
1594 }
1595 } else {
1596 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001597 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001598 || !schema) {
1599 result = NULL;
1600 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001601 }
1602 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001603 LY_TREE_FOR(result ? result->child : start, iter) {
1604 if (iter->schema == schema) {
1605 /* move in data tree according to returned schema */
1606 result = iter;
1607 break;
1608 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001609 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001610 if (!iter) {
1611 /* instance not found */
1612 result = NULL;
1613 break;
1614 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001615 }
1616 free(str);
1617
1618 return result;
1619}
1620
Radek Krejci1a9c3612017-04-24 14:49:43 +02001621int
Michal Vasko50576712017-07-28 12:28:33 +02001622schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1623 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001624{
1625 const struct lys_module *prefix_mod;
1626
Michal Vasko50576712017-07-28 12:28:33 +02001627 /* name check */
1628 if ((name[0] != '*') && (name[0] != '.') && (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len])) {
1629 return 1;
1630 }
1631
Radek Krejcibdf92362016-04-08 14:43:34 +02001632 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001633 if (mod_name) {
1634 prefix_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
1635 if (!prefix_mod) {
1636 return -1;
1637 }
1638 } else {
1639 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001640 }
1641 if (prefix_mod != lys_node_module(sibling)) {
1642 return 1;
1643 }
1644
Michal Vasko50576712017-07-28 12:28:33 +02001645 /* match */
1646 switch (name[0]) {
1647 case '*':
1648 return 2;
1649 case '.':
1650 return 3;
1651 default:
Radek Krejcibdf92362016-04-08 14:43:34 +02001652 return 0;
1653 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001654}
1655
Michal Vasko50576712017-07-28 12:28:33 +02001656/* keys do not have to be ordered and do not have to be all of them */
1657static int
1658resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1659 const struct lys_module *cur_module, int *nodeid_end)
1660{
1661 int mod_len, nam_len, has_predicate, r, i;
1662 const char *model, *name;
1663 struct lys_node_list *list;
1664
1665 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1666 return 1;
1667 }
1668
1669 list = (struct lys_node_list *)node;
1670 do {
1671 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1672 if (r < 1) {
1673 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
1674 return -1;
1675 }
1676 nodeid += r;
1677
1678 if (node->nodetype == LYS_LEAFLIST) {
1679 /* just check syntax */
1680 if (model || !name || (name[0] != '.') || has_predicate) {
1681 return 1;
1682 }
1683 break;
1684 } else {
1685 /* check the key */
1686 for (i = 0; i < list->keys_size; ++i) {
1687 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1688 continue;
1689 }
1690 if (model) {
1691 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1692 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1693 continue;
1694 }
1695 } else {
1696 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1697 continue;
1698 }
1699 }
1700
1701 /* match */
1702 break;
1703 }
1704
1705 if (i == list->keys_size) {
1706 return 1;
1707 }
1708 }
1709 } while (has_predicate);
1710
1711 if (!nodeid[0]) {
1712 *nodeid_end = 1;
1713 }
1714 return 0;
1715}
1716
1717/* start - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001718 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001719int
Michal Vasko50576712017-07-28 12:28:33 +02001720resolve_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
1721 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001722{
Michal Vaskobb520442017-05-23 10:55:18 +02001723 const char *name, *mod_name, *id;
Michal Vasko50576712017-07-28 12:28:33 +02001724 const struct lys_node *sibling, *start_parent, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001725 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001726 int r, nam_len, mod_name_len = 0, is_relative = -1, all_desc, has_predicate, nodeid_end = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001727 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001728 const struct lys_module *start_mod, *aux_mod;
Michal Vasko50576712017-07-28 12:28:33 +02001729 char *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001730
Michal Vasko50576712017-07-28 12:28:33 +02001731 assert(nodeid && (start || cur_module) && ret);
1732 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001733
Michal Vasko50576712017-07-28 12:28:33 +02001734 if (!cur_module) {
1735 cur_module = lys_node_module(start);
1736 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001737 id = nodeid;
1738
Michal Vasko50576712017-07-28 12:28:33 +02001739 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1740 (extended ? &all_desc : NULL), extended);
1741 if (r < 1) {
1742 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1743 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001744 }
1745 id += r;
1746
Michal Vasko50576712017-07-28 12:28:33 +02001747 if (is_relative && !start) {
1748 LOGINT;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001749 return -1;
1750 }
1751
1752 /* descendant-schema-nodeid */
1753 if (is_relative) {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001754 cur_module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001755 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001756
Michal Vasko3edeaf72016-02-11 13:17:43 +01001757 /* absolute-schema-nodeid */
1758 } else {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001759 start_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001760 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001761 str = strndup(mod_name, mod_name_len);
1762 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1763 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001764 return -1;
1765 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001766 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001767 }
1768
1769 while (1) {
1770 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001771 last_aug = NULL;
1772
1773 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001774 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1775 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001776 /* we are getting into another module (augment) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001777 aux_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskobb520442017-05-23 10:55:18 +02001778 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001779 str = strndup(mod_name, mod_name_len);
1780 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1781 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001782 return -1;
1783 }
1784 } else {
Michal Vasko17315772017-07-10 15:15:39 +02001785 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001786 * because this module may be not implemented and it augments something in another module and
1787 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001788 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001789 }
1790
1791 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001792 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001793get_next_augment:
1794 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1795 }
1796 }
1797
1798 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001799 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001800 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1801
1802 /* resolve predicate */
1803 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1804 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1805 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001806 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001807 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001808 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001809 }
Michal Vasko50576712017-07-28 12:28:33 +02001810 } else if (!id[0]) {
1811 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001812 }
Michal Vasko50576712017-07-28 12:28:33 +02001813
1814 if (r == 0) {
1815 /* one matching result */
1816 if (nodeid_end) {
1817 *ret = ly_set_new();
1818 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1819 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1820 } else {
1821 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1822 return -1;
1823 }
1824 start_parent = sibling;
1825 }
1826 break;
1827 } else if (r == 1) {
1828 continue;
1829 } else if (r == 2) {
1830 /* "*" */
1831 if (!*ret) {
1832 *ret = ly_set_new();
1833 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1834 }
1835 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1836 if (all_desc) {
1837 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1838 if (elem != sibling) {
1839 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1840 }
1841
1842 LY_TREE_DFS_END(sibling, next, elem);
1843 }
1844 }
1845 } else if (r == 3) {
1846 /* "." */
1847 if (!*ret) {
1848 *ret = ly_set_new();
1849 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1850 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1851 }
1852 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1853 if (all_desc) {
1854 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1855 if (elem != sibling) {
1856 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1857 }
1858
1859 LY_TREE_DFS_END(sibling, next, elem);
1860 }
1861 }
1862 } else {
1863 LOGINT;
1864 return -1;
1865 }
1866 }
1867
1868 /* skip predicate */
1869 if (extended && has_predicate) {
1870 while (id[0] == '[') {
1871 id = strchr(id, ']');
1872 if (!id) {
1873 LOGINT;
1874 return -1;
1875 }
1876 ++id;
1877 }
1878 }
1879
1880 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1881 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001882 }
1883
1884 /* no match */
1885 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001886 if (last_aug) {
1887 /* it still could be in another augment */
1888 goto get_next_augment;
1889 }
Michal Vasko50576712017-07-28 12:28:33 +02001890 if (no_node_error) {
1891 str = strndup(nodeid, (name - nodeid) + nam_len);
1892 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1893 free(str);
1894 return -1;
1895 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001896 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001897 return EXIT_SUCCESS;
1898 }
1899
Michal Vasko50576712017-07-28 12:28:33 +02001900 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1901 (extended ? &all_desc : NULL), extended);
1902 if (r < 1) {
1903 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1904 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001905 }
1906 id += r;
1907 }
1908
1909 /* cannot get here */
1910 LOGINT;
1911 return -1;
1912}
1913
Radek Krejcif3c71de2016-04-11 12:45:46 +02001914/* unique, refine,
1915 * >0 - unexpected char on position (ret - 1),
1916 * 0 - ok (but ret can still be NULL),
1917 * -1 - error,
1918 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001919int
1920resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001921 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001922{
1923 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001924 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001925 int r, nam_len, mod_name_len, is_relative = -1;
1926 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001927 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001928
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001929 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001930 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001931
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001932 if (!start) {
1933 /* leaf not found */
1934 return 0;
1935 }
1936
Michal Vasko3edeaf72016-02-11 13:17:43 +01001937 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02001938 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001939
Michal Vasko50576712017-07-28 12:28:33 +02001940 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001941 return ((id - nodeid) - r) + 1;
1942 }
1943 id += r;
1944
1945 if (!is_relative) {
1946 return -1;
1947 }
1948
Michal Vasko24476fa2017-03-08 12:33:48 +01001949 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001950 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001951 start_parent = lys_parent(start_parent);
1952 }
1953
Michal Vasko3edeaf72016-02-11 13:17:43 +01001954 while (1) {
1955 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001956 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001957 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001958 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
1959 if (r == 0) {
1960 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001961 if (!(sibling->nodetype & ret_nodetype)) {
1962 /* wrong node type, too bad */
1963 continue;
1964 }
1965 *ret = sibling;
1966 return EXIT_SUCCESS;
1967 }
Michal Vasko50576712017-07-28 12:28:33 +02001968 start_parent = sibling;
1969 break;
1970 } else if (r == 1) {
1971 continue;
1972 } else {
1973 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001974 }
1975 }
1976
1977 /* no match */
1978 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001979 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001980 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001981 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1982 *ret = NULL;
1983 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001984 }
1985
Michal Vasko50576712017-07-28 12:28:33 +02001986 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001987 return ((id - nodeid) - r) + 1;
1988 }
1989 id += r;
1990 }
1991
1992 /* cannot get here */
1993 LOGINT;
1994 return -1;
1995}
1996
1997/* choice default */
1998int
1999resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2000{
2001 /* cannot actually be a path */
2002 if (strchr(nodeid, '/')) {
2003 return -1;
2004 }
2005
Michal Vaskodc300b02017-04-07 14:09:20 +02002006 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002007}
2008
2009/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2010static int
2011resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2012{
2013 const struct lys_module *module;
2014 const char *mod_prefix, *name;
2015 int i, mod_prefix_len, nam_len;
2016
2017 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002018 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len, NULL, 0)) < 1) || nodeid[i]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002019 return -i + 1;
2020 }
2021
2022 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
2023 if (!module) {
2024 return -1;
2025 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002026 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002027 start = module->data;
2028 }
2029
2030 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2031
2032 return EXIT_SUCCESS;
2033}
2034
2035int
2036resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2037 const struct lys_node **ret)
2038{
2039 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002040 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002041 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002042 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002043
2044 assert(nodeid && module && ret);
2045 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2046
2047 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002048 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002049
Michal Vasko50576712017-07-28 12:28:33 +02002050 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002051 return ((id - nodeid) - r) + 1;
2052 }
2053 id += r;
2054
2055 if (is_relative) {
2056 return -1;
2057 }
2058
2059 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01002060 if (!abs_start_mod) {
2061 return -1;
2062 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002063
2064 while (1) {
2065 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002066 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01002067 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
Michal Vasko50576712017-07-28 12:28:33 +02002068 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2069 if (r == 0) {
2070 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002071 if (!(sibling->nodetype & ret_nodetype)) {
2072 /* wrong node type, too bad */
2073 continue;
2074 }
2075 *ret = sibling;
2076 return EXIT_SUCCESS;
2077 }
Michal Vasko50576712017-07-28 12:28:33 +02002078 start_parent = sibling;
2079 break;
2080 } else if (r == 1) {
2081 continue;
2082 } else {
2083 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002084 }
2085 }
2086
2087 /* no match */
2088 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002089 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002090 return EXIT_SUCCESS;
2091 }
2092
Michal Vasko50576712017-07-28 12:28:33 +02002093 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL, NULL, 0)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002094 return ((id - nodeid) - r) + 1;
2095 }
2096 id += r;
2097 }
2098
2099 /* cannot get here */
2100 LOGINT;
2101 return -1;
2102}
2103
Michal Vaskoe733d682016-03-14 09:08:27 +01002104static int
Michal Vasko50576712017-07-28 12:28:33 +02002105resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002106{
Michal Vaskof359b022017-07-04 13:50:04 +02002107 const char *mod_name, *name;
2108 int mod_name_len, nam_len, has_predicate, i;
2109 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002110
Michal Vaskof359b022017-07-04 13:50:04 +02002111 if (((i = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002112 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002113 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002114 return -1;
2115 }
2116
2117 predicate += i;
2118 *parsed += i;
2119
Michal Vasko58c2aab2017-01-05 10:02:05 +01002120 if (!isdigit(name[0])) {
2121 for (i = 0; i < list->keys_size; ++i) {
Michal Vaskof359b022017-07-04 13:50:04 +02002122 key = (struct lys_node *)list->keys[i];
2123 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002124 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002125 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002126 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002127
Michal Vasko58c2aab2017-01-05 10:02:05 +01002128 if (i == list->keys_size) {
2129 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2130 return -1;
2131 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002132 }
2133
2134 /* more predicates? */
2135 if (has_predicate) {
Michal Vasko50576712017-07-28 12:28:33 +02002136 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002137 }
2138
2139 return 0;
2140}
2141
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002142/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002143const struct lys_node *
Michal Vaskob3744402017-08-03 14:23:58 +02002144resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start, int output)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002145{
Michal Vasko10728b52016-04-07 14:26:29 +02002146 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002147 const char *name, *mod_name, *id;
Michal Vaskob3744402017-08-03 14:23:58 +02002148 const struct lys_node *sibling, *start_parent, *parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002149 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002150 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko50576712017-07-28 12:28:33 +02002151 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002152
Michal Vasko3547c532016-03-14 09:40:50 +01002153 assert(nodeid && (ctx || start));
2154 if (!ctx) {
2155 ctx = start->module->ctx;
2156 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002157
2158 id = nodeid;
2159
Michal Vasko50576712017-07-28 12:28:33 +02002160 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002161 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002162 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002163 }
2164 id += r;
2165
2166 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002167 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002168 start_parent = start;
2169 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2170 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002171 }
Michal Vasko50576712017-07-28 12:28:33 +02002172 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002173 } else {
2174 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002175 str = strndup(nodeid, (name + nam_len) - nodeid);
2176 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2177 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002178 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002179 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2180 LOGINT;
2181 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002182 }
2183
Michal Vasko971a3ca2016-04-01 13:09:29 +02002184 if (ly_buf_used && module_name[0]) {
2185 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2186 }
2187 ly_buf_used++;
2188
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002189 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002190 module_name[mod_name_len] = '\0';
Michal Vasko50576712017-07-28 12:28:33 +02002191 module = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002192
2193 if (buf_backup) {
2194 /* return previous internal buffer content */
2195 strcpy(module_name, buf_backup);
2196 free(buf_backup);
2197 buf_backup = NULL;
2198 }
2199 ly_buf_used--;
2200
Michal Vasko50576712017-07-28 12:28:33 +02002201 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002202 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2203 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2204 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002205 return NULL;
2206 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002207 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002208
2209 /* now it's as if there was no module name */
2210 mod_name = NULL;
2211 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002212 }
2213
Michal Vasko50576712017-07-28 12:28:33 +02002214 prev_mod = module;
2215
Michal Vasko3edeaf72016-02-11 13:17:43 +01002216 while (1) {
2217 sibling = NULL;
Michal Vaskob3744402017-08-03 14:23:58 +02002218 while ((sibling = lys_getnext(sibling, start_parent, module, 0))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002219 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002220 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vaskob3744402017-08-03 14:23:58 +02002221 /* output check */
2222 for (parent = lys_parent(sibling); parent && !(parent->nodetype & (LYS_INPUT | LYS_OUTPUT)); parent = lys_parent(parent));
2223 if (parent) {
2224 if (output && (parent->nodetype == LYS_INPUT)) {
2225 continue;
2226 } else if (!output && (parent->nodetype == LYS_OUTPUT)) {
2227 continue;
2228 }
2229 }
2230
Michal Vasko3edeaf72016-02-11 13:17:43 +01002231 /* module check */
2232 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002233 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002234 LOGINT;
2235 return NULL;
2236 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002237
2238 if (ly_buf_used && module_name[0]) {
2239 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2240 }
2241 ly_buf_used++;
2242
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002243 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002244 module_name[mod_name_len] = '\0';
2245 /* will also find an augment module */
2246 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002247
2248 if (buf_backup) {
2249 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002250 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002251 free(buf_backup);
2252 buf_backup = NULL;
2253 }
2254 ly_buf_used--;
2255
Michal Vasko3edeaf72016-02-11 13:17:43 +01002256 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002257 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2258 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2259 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002260 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002261 }
2262 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002263 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002264 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002265 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002266 continue;
2267 }
2268
Michal Vaskoe733d682016-03-14 09:08:27 +01002269 /* do we have some predicates on it? */
2270 if (has_predicate) {
2271 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002272 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vaskof359b022017-07-04 13:50:04 +02002273 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002274 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2275 return NULL;
2276 }
2277 } else if (sibling->nodetype == LYS_LIST) {
Michal Vasko50576712017-07-28 12:28:33 +02002278 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002279 return NULL;
2280 }
2281 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002282 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002283 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002284 }
2285 id += r;
2286 }
2287
Michal Vasko3edeaf72016-02-11 13:17:43 +01002288 /* the result node? */
2289 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002290 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002291 }
2292
Michal Vaskodc300b02017-04-07 14:09:20 +02002293 /* move down the tree, if possible */
2294 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2295 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2296 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002297 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002298 start_parent = sibling;
Michal Vasko50576712017-07-28 12:28:33 +02002299
2300 /* update prev mod */
2301 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002302 break;
2303 }
2304 }
2305
2306 /* no match */
2307 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002308 str = strndup(nodeid, (name + nam_len) - nodeid);
2309 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2310 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002311 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002312 }
2313
Michal Vasko50576712017-07-28 12:28:33 +02002314 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002315 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002316 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002317 }
2318 id += r;
2319 }
2320
2321 /* cannot get here */
2322 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002323 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002324}
2325
Michal Vasko22448d32016-03-16 13:17:29 +01002326static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002327resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko50576712017-07-28 12:28:33 +02002328 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002329{
Michal Vaskof359b022017-07-04 13:50:04 +02002330 const char *mod_name, *name, *value, *key_val;
2331 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002332 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002333 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002334
Radek Krejci61a86c62016-03-24 11:06:44 +01002335 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002336 assert(node->schema->nodetype == LYS_LIST);
2337
Michal Vasko53adfc72017-01-06 10:39:10 +01002338 /* is the predicate a number? */
Michal Vaskof359b022017-07-04 13:50:04 +02002339 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko53adfc72017-01-06 10:39:10 +01002340 || !strncmp(name, ".", nam_len)) {
2341 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2342 return -1;
2343 }
2344
2345 if (isdigit(name[0])) {
2346 if (position == atoi(name)) {
2347 /* match */
2348 *parsed += r;
2349 return 0;
2350 } else {
2351 /* not a match */
2352 return 1;
2353 }
2354 }
2355
2356 if (!((struct lys_node_list *)node->schema)->keys_size) {
2357 /* no keys in schema - causes an error later */
2358 return 0;
2359 }
2360
Michal Vaskof29903d2016-04-18 13:13:10 +02002361 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002362 if (!key) {
2363 /* it is not a position, so we need a key for it to be a match */
2364 return 1;
2365 }
2366
2367 /* go through all the keys */
2368 i = 0;
2369 goto check_parsed_values;
2370
2371 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002372 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002373 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002374 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002375 }
2376
Michal Vaskof359b022017-07-04 13:50:04 +02002377 if (((r = parse_schema_json_predicate(predicate, &mod_name, &mod_name_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002378 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002379 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002380 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002381 }
2382
Michal Vasko53adfc72017-01-06 10:39:10 +01002383check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002384 predicate += r;
2385 *parsed += r;
2386
Michal Vaskof29903d2016-04-18 13:13:10 +02002387 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002388 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002389 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002390 }
2391
Michal Vaskof359b022017-07-04 13:50:04 +02002392 if (mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002393 /* specific module, check that the found key is from that module */
Michal Vaskof359b022017-07-04 13:50:04 +02002394 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2395 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
2396 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2397 return -1;
2398 }
Michal Vasko50576712017-07-28 12:28:33 +02002399
2400 /* but if the module is the same as the parent, it should have been omitted */
2401 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
2402 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2403 return -1;
2404 }
Michal Vaskof359b022017-07-04 13:50:04 +02002405 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002406 /* no module, so it must be the same as the list (parent) */
2407 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vaskof359b022017-07-04 13:50:04 +02002408 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2409 return -1;
2410 }
2411 }
2412
Michal Vasko9ba34de2016-12-07 12:21:19 +01002413 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002414 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002415 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2416 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002417 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2418 } else {
2419 key_val = key->value_str;
2420 }
2421
Michal Vasko22448d32016-03-16 13:17:29 +01002422 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002423 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002424 return 1;
2425 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002426
2427 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002428 }
2429
2430 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002431 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002432 return -1;
2433 }
2434
2435 return 0;
2436}
2437
Radek Krejci45826012016-08-24 15:07:57 +02002438/**
2439 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2440 *
2441 * @param[in] nodeid Node data path to find
2442 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2443 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2444 * @param[out] parsed Number of characters processed in \p id
2445 * @return The closes parent (or the node itself) from the path
2446 */
Michal Vasko22448d32016-03-16 13:17:29 +01002447struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002448resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2449 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002450{
Michal Vasko10728b52016-04-07 14:26:29 +02002451 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002452 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002453 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002454 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002455 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002456 struct lyd_node_leaf_list *llist;
Michal Vasko50576712017-07-28 12:28:33 +02002457 const struct lys_module *prefix_mod, *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002458 struct ly_ctx *ctx;
2459
2460 assert(nodeid && start && parsed);
2461
2462 ctx = start->schema->module->ctx;
2463 id = nodeid;
2464
Michal Vasko50576712017-07-28 12:28:33 +02002465 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002466 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002467 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002468 return NULL;
2469 }
2470 id += r;
2471 /* add it to parsed only after the data node was actually found */
2472 last_parsed = r;
2473
2474 if (is_relative) {
Michal Vasko50576712017-07-28 12:28:33 +02002475 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002476 start = start->child;
2477 } else {
2478 for (; start->parent; start = start->parent);
Michal Vasko50576712017-07-28 12:28:33 +02002479 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002480 }
2481
2482 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002483 list_instance_position = 0;
2484
Michal Vasko22448d32016-03-16 13:17:29 +01002485 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002486 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002487 if (lys_parent(sibling->schema)) {
2488 if (options & LYD_PATH_OPT_OUTPUT) {
2489 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002490 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002491 *parsed = -1;
2492 return NULL;
2493 }
2494 } else {
2495 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002496 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002497 *parsed = -1;
2498 return NULL;
2499 }
2500 }
2501 }
2502
Michal Vasko22448d32016-03-16 13:17:29 +01002503 /* name match */
2504 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2505
2506 /* module check */
2507 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002508 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002509 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002510 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002511 return NULL;
2512 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002513
2514 if (ly_buf_used && module_name[0]) {
2515 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2516 }
2517 ly_buf_used++;
2518
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002519 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002520 module_name[mod_name_len] = '\0';
2521 /* will also find an augment module */
2522 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002523
2524 if (buf_backup) {
2525 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002526 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002527 free(buf_backup);
2528 buf_backup = NULL;
2529 }
2530 ly_buf_used--;
2531
Michal Vasko22448d32016-03-16 13:17:29 +01002532 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002533 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2534 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2535 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002536 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002537 return NULL;
2538 }
2539 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002540 prefix_mod = prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002541 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002542 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002543 continue;
2544 }
2545
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002546 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002547 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002548 llist = (struct lyd_node_leaf_list *)sibling;
2549
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002550 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002551 if (has_predicate) {
Michal Vaskof359b022017-07-04 13:50:04 +02002552 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2553 &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002554 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2555 *parsed = -1;
2556 return NULL;
2557 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002558 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2559 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2560 *parsed = -1;
2561 return NULL;
2562 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002563 } else {
2564 r = 0;
2565 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002566 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002567 }
2568 }
2569
Michal Vasko9ba34de2016-12-07 12:21:19 +01002570 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002571 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002572 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2573 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002574 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2575 } else {
2576 data_val = llist->value_str;
2577 }
2578
2579 if ((!llist_value && data_val && data_val[0])
2580 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002581 continue;
2582 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002583
Michal Vaskof0a50972016-10-19 11:33:55 +02002584 id += r;
2585 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002586 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002587
Radek Krejci45826012016-08-24 15:07:57 +02002588 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002589 /* 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 +01002590 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002591 /* none match */
2592 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002593 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002594
2595 ++list_instance_position;
2596 r = 0;
Michal Vasko50576712017-07-28 12:28:33 +02002597 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002598 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002599 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002600 return NULL;
2601 } else if (ret == 1) {
2602 /* this list instance does not match */
2603 continue;
2604 }
2605 id += r;
2606 last_parsed += r;
2607 }
2608
2609 *parsed += last_parsed;
2610
2611 /* the result node? */
2612 if (!id[0]) {
2613 return sibling;
2614 }
2615
2616 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002617 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002618 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002619 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002620 return NULL;
2621 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002622 last_match = sibling;
Michal Vasko50576712017-07-28 12:28:33 +02002623 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002624 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002625 break;
2626 }
2627 }
2628
2629 /* no match, return last match */
2630 if (!sibling) {
2631 return last_match;
2632 }
2633
Michal Vasko50576712017-07-28 12:28:33 +02002634 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate, NULL, 0)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002635 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002636 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002637 return NULL;
2638 }
2639 id += r;
2640 last_parsed = r;
2641 }
2642
2643 /* cannot get here */
2644 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002645 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002646 return NULL;
2647}
2648
Michal Vasko3edeaf72016-02-11 13:17:43 +01002649/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002650 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002651 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002652 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002653 * @param[in] str_restr Restriction as a string.
2654 * @param[in] type Type of the restriction.
2655 * @param[out] ret Final interval structure that starts with
2656 * the interval of the initial type, continues with intervals
2657 * of any superior types derived from the initial one, and
2658 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002659 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002660 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002661 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002662int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002663resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664{
2665 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002666 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002667 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002668 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002669 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002670 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002671 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002672
2673 switch (type->base) {
2674 case LY_TYPE_BINARY:
2675 kind = 0;
2676 local_umin = 0;
2677 local_umax = 18446744073709551615UL;
2678
2679 if (!str_restr && type->info.binary.length) {
2680 str_restr = type->info.binary.length->expr;
2681 }
2682 break;
2683 case LY_TYPE_DEC64:
2684 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002685 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2686 local_fmax = __INT64_C(9223372036854775807);
2687 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002688
2689 if (!str_restr && type->info.dec64.range) {
2690 str_restr = type->info.dec64.range->expr;
2691 }
2692 break;
2693 case LY_TYPE_INT8:
2694 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002695 local_smin = __INT64_C(-128);
2696 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002697
2698 if (!str_restr && type->info.num.range) {
2699 str_restr = type->info.num.range->expr;
2700 }
2701 break;
2702 case LY_TYPE_INT16:
2703 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002704 local_smin = __INT64_C(-32768);
2705 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002706
2707 if (!str_restr && type->info.num.range) {
2708 str_restr = type->info.num.range->expr;
2709 }
2710 break;
2711 case LY_TYPE_INT32:
2712 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002713 local_smin = __INT64_C(-2147483648);
2714 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002715
2716 if (!str_restr && type->info.num.range) {
2717 str_restr = type->info.num.range->expr;
2718 }
2719 break;
2720 case LY_TYPE_INT64:
2721 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002722 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2723 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002724
2725 if (!str_restr && type->info.num.range) {
2726 str_restr = type->info.num.range->expr;
2727 }
2728 break;
2729 case LY_TYPE_UINT8:
2730 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002731 local_umin = __UINT64_C(0);
2732 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002733
2734 if (!str_restr && type->info.num.range) {
2735 str_restr = type->info.num.range->expr;
2736 }
2737 break;
2738 case LY_TYPE_UINT16:
2739 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002740 local_umin = __UINT64_C(0);
2741 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002742
2743 if (!str_restr && type->info.num.range) {
2744 str_restr = type->info.num.range->expr;
2745 }
2746 break;
2747 case LY_TYPE_UINT32:
2748 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002749 local_umin = __UINT64_C(0);
2750 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002751
2752 if (!str_restr && type->info.num.range) {
2753 str_restr = type->info.num.range->expr;
2754 }
2755 break;
2756 case LY_TYPE_UINT64:
2757 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002758 local_umin = __UINT64_C(0);
2759 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002760
2761 if (!str_restr && type->info.num.range) {
2762 str_restr = type->info.num.range->expr;
2763 }
2764 break;
2765 case LY_TYPE_STRING:
2766 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002767 local_umin = __UINT64_C(0);
2768 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002769
2770 if (!str_restr && type->info.str.length) {
2771 str_restr = type->info.str.length->expr;
2772 }
2773 break;
2774 default:
2775 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002776 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 }
2778
2779 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002780 if (type->der) {
2781 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002782 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002783 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002784 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002785 assert(!intv || (intv->kind == kind));
2786 }
2787
2788 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002789 /* we do not have any restriction, return superior ones */
2790 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002791 return EXIT_SUCCESS;
2792 }
2793
2794 /* adjust local min and max */
2795 if (intv) {
2796 tmp_intv = intv;
2797
2798 if (kind == 0) {
2799 local_umin = tmp_intv->value.uval.min;
2800 } else if (kind == 1) {
2801 local_smin = tmp_intv->value.sval.min;
2802 } else if (kind == 2) {
2803 local_fmin = tmp_intv->value.fval.min;
2804 }
2805
2806 while (tmp_intv->next) {
2807 tmp_intv = tmp_intv->next;
2808 }
2809
2810 if (kind == 0) {
2811 local_umax = tmp_intv->value.uval.max;
2812 } else if (kind == 1) {
2813 local_smax = tmp_intv->value.sval.max;
2814 } else if (kind == 2) {
2815 local_fmax = tmp_intv->value.fval.max;
2816 }
2817 }
2818
2819 /* finally parse our restriction */
2820 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002821 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002822 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002823 if (!tmp_local_intv) {
2824 assert(!local_intv);
2825 local_intv = malloc(sizeof *local_intv);
2826 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002827 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002828 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002829 tmp_local_intv = tmp_local_intv->next;
2830 }
Radek Krejcia8d111f2017-05-31 13:57:37 +02002831 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM, error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002832
2833 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002834 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002835 tmp_local_intv->next = NULL;
2836
2837 /* min */
2838 ptr = seg_ptr;
2839 while (isspace(ptr[0])) {
2840 ++ptr;
2841 }
2842 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2843 if (kind == 0) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002844 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002845 } else if (kind == 1) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002846 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002847 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002848 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2849 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2850 goto error;
2851 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002852 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002853 } else if (!strncmp(ptr, "min", 3)) {
2854 if (kind == 0) {
2855 tmp_local_intv->value.uval.min = local_umin;
2856 } else if (kind == 1) {
2857 tmp_local_intv->value.sval.min = local_smin;
2858 } else if (kind == 2) {
2859 tmp_local_intv->value.fval.min = local_fmin;
2860 }
2861
2862 ptr += 3;
2863 } else if (!strncmp(ptr, "max", 3)) {
2864 if (kind == 0) {
2865 tmp_local_intv->value.uval.min = local_umax;
2866 } else if (kind == 1) {
2867 tmp_local_intv->value.sval.min = local_smax;
2868 } else if (kind == 2) {
2869 tmp_local_intv->value.fval.min = local_fmax;
2870 }
2871
2872 ptr += 3;
2873 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002874 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002875 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002876 }
2877
2878 while (isspace(ptr[0])) {
2879 ptr++;
2880 }
2881
2882 /* no interval or interval */
2883 if ((ptr[0] == '|') || !ptr[0]) {
2884 if (kind == 0) {
2885 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2886 } else if (kind == 1) {
2887 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2888 } else if (kind == 2) {
2889 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2890 }
2891 } else if (!strncmp(ptr, "..", 2)) {
2892 /* skip ".." */
2893 ptr += 2;
2894 while (isspace(ptr[0])) {
2895 ++ptr;
2896 }
2897
2898 /* max */
2899 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2900 if (kind == 0) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002901 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002902 } else if (kind == 1) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002903 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002904 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002905 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2906 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2907 goto error;
2908 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002909 }
2910 } else if (!strncmp(ptr, "max", 3)) {
2911 if (kind == 0) {
2912 tmp_local_intv->value.uval.max = local_umax;
2913 } else if (kind == 1) {
2914 tmp_local_intv->value.sval.max = local_smax;
2915 } else if (kind == 2) {
2916 tmp_local_intv->value.fval.max = local_fmax;
2917 }
2918 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002919 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002920 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002921 }
2922 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002923 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002924 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002925 }
2926
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002927 /* check min and max in correct order*/
2928 if (kind == 0) {
2929 /* current segment */
2930 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2931 goto error;
2932 }
2933 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2934 goto error;
2935 }
2936 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002937 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002938 goto error;
2939 }
2940 } else if (kind == 1) {
2941 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2942 goto error;
2943 }
2944 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2945 goto error;
2946 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002947 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002948 goto error;
2949 }
2950 } else if (kind == 2) {
2951 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2952 goto error;
2953 }
2954 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2955 goto error;
2956 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002957 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002958 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002959 goto error;
2960 }
2961 }
2962
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002963 /* next segment (next OR) */
2964 seg_ptr = strchr(seg_ptr, '|');
2965 if (!seg_ptr) {
2966 break;
2967 }
2968 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002969 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002970 }
2971
2972 /* check local restrictions against superior ones */
2973 if (intv) {
2974 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002975 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002976
2977 while (tmp_local_intv && tmp_intv) {
2978 /* reuse local variables */
2979 if (kind == 0) {
2980 local_umin = tmp_local_intv->value.uval.min;
2981 local_umax = tmp_local_intv->value.uval.max;
2982
2983 /* it must be in this interval */
2984 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2985 /* this interval is covered, next one */
2986 if (local_umax <= tmp_intv->value.uval.max) {
2987 tmp_local_intv = tmp_local_intv->next;
2988 continue;
2989 /* ascending order of restrictions -> fail */
2990 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002991 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002992 }
2993 }
2994 } else if (kind == 1) {
2995 local_smin = tmp_local_intv->value.sval.min;
2996 local_smax = tmp_local_intv->value.sval.max;
2997
2998 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2999 if (local_smax <= tmp_intv->value.sval.max) {
3000 tmp_local_intv = tmp_local_intv->next;
3001 continue;
3002 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003003 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003004 }
3005 }
3006 } else if (kind == 2) {
3007 local_fmin = tmp_local_intv->value.fval.min;
3008 local_fmax = tmp_local_intv->value.fval.max;
3009
Michal Vasko4d1f0482016-09-19 14:35:06 +02003010 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003011 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003012 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003013 tmp_local_intv = tmp_local_intv->next;
3014 continue;
3015 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003016 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003017 }
3018 }
3019 }
3020
3021 tmp_intv = tmp_intv->next;
3022 }
3023
3024 /* some interval left uncovered -> fail */
3025 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003026 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003027 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003028 }
3029
Michal Vaskoaeb51802016-04-11 10:58:47 +02003030 /* append the local intervals to all the intervals of the superior types, return it all */
3031 if (intv) {
3032 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3033 tmp_intv->next = local_intv;
3034 } else {
3035 intv = local_intv;
3036 }
3037 *ret = intv;
3038
3039 return EXIT_SUCCESS;
3040
3041error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003042 while (intv) {
3043 tmp_intv = intv->next;
3044 free(intv);
3045 intv = tmp_intv;
3046 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003047 while (local_intv) {
3048 tmp_local_intv = local_intv->next;
3049 free(local_intv);
3050 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003051 }
3052
Michal Vaskoaeb51802016-04-11 10:58:47 +02003053 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003054}
3055
Michal Vasko730dfdf2015-08-11 14:48:05 +02003056/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003057 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3058 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003059 *
3060 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003061 * @param[in] mod_name Typedef name module name.
3062 * @param[in] module Main module.
3063 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003064 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003065 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003066 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003067 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003068int
Michal Vasko1e62a092015-12-01 12:27:20 +01003069resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3070 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003071{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003072 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003073 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003074 int tpdf_size;
3075
Michal Vasko1dca6882015-10-22 14:29:42 +02003076 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003077 /* no prefix, try built-in types */
3078 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003079 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003080 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003081 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003082 }
3083 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003084 }
3085 }
3086 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003087 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003088 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003089 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003090 }
3091 }
3092
Michal Vasko1dca6882015-10-22 14:29:42 +02003093 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003094 /* search in local typedefs */
3095 while (parent) {
3096 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003097 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003098 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3099 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003100 break;
3101
Radek Krejci76512572015-08-04 09:47:08 +02003102 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003103 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3104 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003105 break;
3106
Radek Krejci76512572015-08-04 09:47:08 +02003107 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003108 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3109 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003110 break;
3111
Radek Krejci76512572015-08-04 09:47:08 +02003112 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003113 case LYS_ACTION:
3114 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3115 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116 break;
3117
Radek Krejci76512572015-08-04 09:47:08 +02003118 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003119 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3120 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003121 break;
3122
Radek Krejci76512572015-08-04 09:47:08 +02003123 case LYS_INPUT:
3124 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003125 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3126 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003127 break;
3128
3129 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003130 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003131 continue;
3132 }
3133
3134 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003135 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003136 match = &tpdf[i];
3137 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003138 }
3139 }
3140
Michal Vaskodcf98e62016-05-05 17:53:53 +02003141 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003142 }
Radek Krejcic071c542016-01-27 14:57:51 +01003143 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003144 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02003145 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003146 if (!module) {
3147 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148 }
3149 }
3150
3151 /* search in top level typedefs */
3152 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003153 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003154 match = &module->tpdf[i];
3155 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003156 }
3157 }
3158
3159 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003160 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003161 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003162 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 +02003163 match = &module->inc[i].submodule->tpdf[j];
3164 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003165 }
3166 }
3167 }
3168
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003169 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003170
3171check_leafref:
3172 if (ret) {
3173 *ret = match;
3174 }
3175 if (match->type.base == LY_TYPE_LEAFREF) {
3176 while (!match->type.info.lref.path) {
3177 match = match->type.der;
3178 assert(match);
3179 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003180 }
3181 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003182}
3183
Michal Vasko1dca6882015-10-22 14:29:42 +02003184/**
3185 * @brief Check the default \p value of the \p type. Logs directly.
3186 *
3187 * @param[in] type Type definition to use.
3188 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003189 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003190 *
3191 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3192 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003193static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003194check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003195{
Radek Krejcibad2f172016-08-02 11:04:15 +02003196 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003197 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003198 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003199 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01003200 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003201
Radek Krejci51673202016-11-01 17:00:32 +01003202 assert(value);
3203
Radek Krejcic13db382016-08-16 10:52:42 +02003204 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003205 /* the type was not resolved yet, nothing to do for now */
3206 return EXIT_FAILURE;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003207 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003208 /* do not check defaults in not implemented module's data */
3209 return EXIT_SUCCESS;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003210 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003211 /* identityrefs are checked when instantiated in data instead of typedef,
3212 * but in typedef the value has to be modified to include the prefix */
3213 if (*value) {
3214 if (strchr(*value, ':')) {
3215 dflt = transform_schema2json(module, *value);
3216 } else {
3217 /* default prefix of the module where the typedef is defined */
3218 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
3219 dflt = lydict_insert_zc(module->ctx, s);
3220 }
3221 lydict_remove(module->ctx, *value);
3222 *value = dflt;
3223 }
3224 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003225 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3226 /* leafref in typedef cannot be checked */
3227 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003228 }
3229
Radek Krejci51673202016-11-01 17:00:32 +01003230 dflt = *value;
3231 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003232 /* we do not have a new default value, so is there any to check even, in some base type? */
3233 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3234 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003235 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003236 break;
3237 }
3238 }
3239
Radek Krejci51673202016-11-01 17:00:32 +01003240 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003241 /* no default value, nothing to check, all is well */
3242 return EXIT_SUCCESS;
3243 }
3244
3245 /* 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)? */
3246 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003247 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003248 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3249 return EXIT_SUCCESS;
3250 } else {
3251 /* check the default value from typedef, but use also the typedef's module
3252 * due to possible searching in imported modules which is expected in
3253 * typedef's module instead of module where the typedef is used */
3254 module = base_tpdf->module;
3255 }
3256 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003257 case LY_TYPE_INST:
3258 case LY_TYPE_LEAFREF:
3259 case LY_TYPE_BOOL:
3260 case LY_TYPE_EMPTY:
3261 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3262 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003263 case LY_TYPE_BITS:
3264 /* the default value must match the restricted list of values, if the type was restricted */
3265 if (type->info.bits.count) {
3266 break;
3267 }
3268 return EXIT_SUCCESS;
3269 case LY_TYPE_ENUM:
3270 /* the default value must match the restricted list of values, if the type was restricted */
3271 if (type->info.enums.count) {
3272 break;
3273 }
3274 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003275 case LY_TYPE_DEC64:
3276 if (type->info.dec64.range) {
3277 break;
3278 }
3279 return EXIT_SUCCESS;
3280 case LY_TYPE_BINARY:
3281 if (type->info.binary.length) {
3282 break;
3283 }
3284 return EXIT_SUCCESS;
3285 case LY_TYPE_INT8:
3286 case LY_TYPE_INT16:
3287 case LY_TYPE_INT32:
3288 case LY_TYPE_INT64:
3289 case LY_TYPE_UINT8:
3290 case LY_TYPE_UINT16:
3291 case LY_TYPE_UINT32:
3292 case LY_TYPE_UINT64:
3293 if (type->info.num.range) {
3294 break;
3295 }
3296 return EXIT_SUCCESS;
3297 case LY_TYPE_STRING:
3298 if (type->info.str.length || type->info.str.patterns) {
3299 break;
3300 }
3301 return EXIT_SUCCESS;
3302 case LY_TYPE_UNION:
3303 /* way too much trouble learning whether we need to check the default again, so just do it */
3304 break;
3305 default:
3306 LOGINT;
3307 return -1;
3308 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003309 } else if (type->base == LY_TYPE_EMPTY) {
3310 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3311 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3312 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003313 }
3314
Michal Vasko1dca6882015-10-22 14:29:42 +02003315 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003316 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003317 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003318 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003319 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Radek Krejcia8d111f2017-05-31 13:57:37 +02003320 LY_CHECK_ERR_RETURN(!node.schema, LOGMEM, -1);
Radek Krejcibad2f172016-08-02 11:04:15 +02003321 node.schema->name = strdup("fake-default");
Radek Krejcia8d111f2017-05-31 13:57:37 +02003322 LY_CHECK_ERR_RETURN(!node.schema->name, LOGMEM; free(node.schema), -1);
Michal Vasko56826402016-03-02 11:11:37 +01003323 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003324 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003325
Radek Krejci37b756f2016-01-18 10:15:03 +01003326 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003327 if (!type->info.lref.target) {
3328 ret = EXIT_FAILURE;
3329 goto finish;
3330 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003331 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003332 if (!ret) {
3333 /* adopt possibly changed default value to its canonical form */
3334 if (*value) {
3335 *value = dflt;
3336 }
3337 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003338 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003339 if (!lyp_parse_value(&((struct lys_node_leaf *)node.schema)->type, &node.value_str, NULL, &node, NULL, 1, 1)) {
Radek Krejci5dca5932016-11-04 14:30:47 +01003340 /* possible forward reference */
3341 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003342 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003343 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003344 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3345 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3346 /* we have refined bits/enums */
3347 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3348 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003349 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003350 }
3351 }
Radek Krejci51673202016-11-01 17:00:32 +01003352 } else {
3353 /* success - adopt canonical form from the node into the default value */
3354 if (dflt != node.value_str) {
3355 /* this can happen only if we have non-inherited default value,
3356 * inherited default values are already in canonical form */
3357 assert(dflt == *value);
3358 *value = node.value_str;
3359 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003360 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003361 }
3362
3363finish:
3364 if (node.value_type == LY_TYPE_BITS) {
3365 free(node.value.bit);
3366 }
3367 free((char *)node.schema->name);
3368 free(node.schema);
3369
3370 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003371}
3372
Michal Vasko730dfdf2015-08-11 14:48:05 +02003373/**
3374 * @brief Check a key for mandatory attributes. Logs directly.
3375 *
3376 * @param[in] key The key to check.
3377 * @param[in] flags What flags to check.
3378 * @param[in] list The list of all the keys.
3379 * @param[in] index Index of the key in the key list.
3380 * @param[in] name The name of the keys.
3381 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003382 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003383 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003384 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003385static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003386check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387{
Radek Krejciadb57612016-02-16 13:34:34 +01003388 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003389 char *dup = NULL;
3390 int j;
3391
3392 /* existence */
3393 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003394 if (name[len] != '\0') {
3395 dup = strdup(name);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003396 LY_CHECK_ERR_RETURN(!dup, LOGMEM, -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003397 dup[len] = '\0';
3398 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003399 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003400 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003401 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003402 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003403 }
3404
3405 /* uniqueness */
3406 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003407 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003408 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003409 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 }
3411 }
3412
3413 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003414 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003415 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003416 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417 }
3418
3419 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003420 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003421 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003422 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 }
3424
3425 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003426 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003427 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003428 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003429 }
3430
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003431 /* key is not placed from augment */
3432 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003433 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003434 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003435 return -1;
3436 }
3437
Radek Krejci3f21ada2016-08-01 13:34:31 +02003438 /* key is not when/if-feature -conditional */
3439 j = 0;
3440 if (key->when || (key->iffeature_size && (j = 1))) {
3441 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003442 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003443 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003444 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003445 }
3446
Michal Vasko0b85aa82016-03-07 14:37:43 +01003447 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003448}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003449
3450/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003451 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003452 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003453 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003454 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003455 *
3456 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3457 */
3458int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003459resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003460{
Radek Krejci581ce772015-11-10 17:22:40 +01003461 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003462 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003463
Michal Vaskodc300b02017-04-07 14:09:20 +02003464 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003465 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003466 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003467 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003468 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003469 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003470 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003471 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003472 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003473 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003474 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003475 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003476 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003477 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003478 }
Radek Krejci581ce772015-11-10 17:22:40 +01003479 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003480 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003481 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003482 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003483 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003484 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003485 }
3486
Radek Krejcicf509982015-12-15 09:22:44 +01003487 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003488 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3489 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003490 return -1;
3491 }
3492
Radek Krejcid09d1a52016-08-11 14:05:45 +02003493 /* check that all unique's targets are of the same config type */
3494 if (*trg_type) {
3495 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3496 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003497 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003498 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3499 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3500 return -1;
3501 }
3502 } else {
3503 /* first unique */
3504 if (leaf->flags & LYS_CONFIG_W) {
3505 *trg_type = 1;
3506 } else {
3507 *trg_type = 2;
3508 }
3509 }
3510
Radek Krejcica7efb72016-01-18 13:06:01 +01003511 /* set leaf's unique flag */
3512 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3513
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003514 return EXIT_SUCCESS;
3515
3516error:
3517
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003518 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003519}
3520
Radek Krejci0c0086a2016-03-24 15:20:28 +01003521void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003522unres_data_del(struct unres_data *unres, uint32_t i)
3523{
3524 /* there are items after the one deleted */
3525 if (i+1 < unres->count) {
3526 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003527 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003528
3529 /* deleting the last item */
3530 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003531 free(unres->node);
3532 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003533 }
3534
3535 /* if there are no items after and it is not the last one, just move the counter */
3536 --unres->count;
3537}
3538
Michal Vasko0491ab32015-08-19 14:28:29 +02003539/**
3540 * @brief Resolve (find) a data node from a specific module. Does not log.
3541 *
3542 * @param[in] mod Module to search in.
3543 * @param[in] name Name of the data node.
3544 * @param[in] nam_len Length of the name.
3545 * @param[in] start Data node to start the search from.
3546 * @param[in,out] parents Resolved nodes. If there are some parents,
3547 * they are replaced (!!) with the resolvents.
3548 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003549 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003550 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003551static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003552resolve_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 +02003553{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003554 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003555 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003556 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557
Michal Vasko23b61ec2015-08-19 11:19:50 +02003558 if (!parents->count) {
3559 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003560 parents->node = malloc(sizeof *parents->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003561 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003562 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003563 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003564 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003565 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003566 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003567 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003568 continue;
3569 }
3570 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003571 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003572 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003573 && node->schema->name[nam_len] == '\0') {
3574 /* matching target */
3575 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003576 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003577 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578 flag = 1;
3579 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003580 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003581 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003582 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003583 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003584 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003585 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003586 }
3587 }
3588 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003589
3590 if (!flag) {
3591 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003592 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003593 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003594 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003595 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003596 }
3597
Michal Vasko0491ab32015-08-19 14:28:29 +02003598 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003599}
3600
Michal Vaskoe27516a2016-10-10 17:55:31 +00003601static int
Michal Vasko1c007172017-03-10 10:20:44 +01003602resolve_schema_leafref_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
Michal Vaskoe27516a2016-10-10 17:55:31 +00003603{
3604 int dep1, dep2;
3605 const struct lys_node *node;
3606
3607 if (lys_parent(op_node)) {
3608 /* inner operation (notif/action) */
3609 if (abs_path) {
3610 return 1;
3611 } else {
3612 /* compare depth of both nodes */
3613 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3614 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3615 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3616 return 1;
3617 }
3618 }
3619 } else {
3620 /* top-level operation (notif/rpc) */
3621 if (op_node != first_node) {
3622 return 1;
3623 }
3624 }
3625
3626 return 0;
3627}
3628
Michal Vasko730dfdf2015-08-11 14:48:05 +02003629/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003630 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003631 *
Michal Vaskobb211122015-08-19 14:03:11 +02003632 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003633 * @param[in] context_node Predicate context node (where the predicate is placed).
3634 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003635 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003636 *
Michal Vasko184521f2015-09-24 13:14:26 +02003637 * @return 0 on forward reference, otherwise the number
3638 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003639 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003640 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003641static int
Michal Vasko1c007172017-03-10 10:20:44 +01003642resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3643 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003644{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003645 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003646 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003648 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3649 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003650
3651 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003652 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003653 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003654 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003655 return -parsed+i;
3656 }
3657 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003658 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003659
Michal Vasko58090902015-08-13 14:04:15 +02003660 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003661 if (sour_pref) {
3662 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3663 } else {
3664 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003665 }
Michal Vaskobb520442017-05-23 10:55:18 +02003666 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003667 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003668 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003669 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003670 }
3671
3672 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003673 dest_parent_times = 0;
3674 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003675 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3676 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003677 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 +02003678 return -parsed;
3679 }
3680 pke_parsed += i;
3681
Radek Krejciadb57612016-02-16 13:34:34 +01003682 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003683 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3684 && !((struct lys_node_augment *)dst_node->parent)->target) {
3685 /* we are in an unresolved augment, cannot evaluate */
3686 LOGVAL(LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
3687 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3688 return 0;
3689 }
3690
Michal Vaskofbaead72016-10-07 10:54:48 +02003691 /* path is supposed to be evaluated in data tree, so we have to skip
3692 * all schema nodes that cannot be instantiated in data tree */
3693 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003694 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003695 dst_node = lys_parent(dst_node));
3696
Michal Vasko1f76a282015-08-04 16:16:53 +02003697 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003698 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003699 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003700 }
3701 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003702 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003703 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003704 if (dest_pref) {
3705 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3706 } else {
3707 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003708 }
Michal Vaskobb520442017-05-23 10:55:18 +02003709 rc = lys_getnext_data(trg_mod, dst_node, dest, dest_len, LYS_CONTAINER | LYS_LIST | LYS_LEAF, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003710 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003711 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003712 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003713 }
3714
Michal Vaskoe27516a2016-10-10 17:55:31 +00003715 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003716 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003717 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003718 }
3719 first_iter = 0;
3720 }
3721
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 if (pke_len == pke_parsed) {
3723 break;
3724 }
3725
Michal Vaskobb520442017-05-23 10:55:18 +02003726 if ((i = parse_path_key_expr(path_key_expr + pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vasko1f76a282015-08-04 16:16:53 +02003727 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003728 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003729 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003730 return -parsed;
3731 }
3732 pke_parsed += i;
3733 }
3734
3735 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003736 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003737 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003738 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003739 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003740 return -parsed;
3741 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003742 } while (has_predicate);
3743
3744 return parsed;
3745}
3746
Michal Vasko730dfdf2015-08-11 14:48:05 +02003747/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003748 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003749 *
Michal Vaskobb211122015-08-19 14:03:11 +02003750 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003751 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003752 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003753 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003754 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003755 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003756static int
Michal Vasko1c007172017-03-10 10:20:44 +01003757resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003758{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003759 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003760 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003761 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02003762 const char *id, *prefix, *name;
3763 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003764 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003765
Michal Vasko184521f2015-09-24 13:14:26 +02003766 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003767 parent_times = 0;
3768 id = path;
3769
Michal Vasko1c007172017-03-10 10:20:44 +01003770 /* find operation schema we are in */
3771 for (op_node = lys_parent(parent);
3772 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3773 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003774
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003775 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003776 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003777 if ((i = parse_path_arg(cur_module, id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Michal Vasko1c007172017-03-10 10:20:44 +01003778 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003779 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003780 }
3781 id += i;
3782
Michal Vaskobb520442017-05-23 10:55:18 +02003783 /* get the current module */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003784 tmp_mod = prefix ? lys_get_import_module(cur_module, NULL, 0, prefix, pref_len) : cur_module;
3785 if (!tmp_mod) {
Michal Vaskobb520442017-05-23 10:55:18 +02003786 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3787 return EXIT_FAILURE;
3788 }
3789 last_aug = NULL;
3790
Michal Vasko184521f2015-09-24 13:14:26 +02003791 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003792 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003793 /* use module data */
3794 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003795
Michal Vasko1f76a282015-08-04 16:16:53 +02003796 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003797 /* we are looking for the right parent */
3798 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003799 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
3800 && !((struct lys_node_augment *)node->parent)->target) {
3801 /* we are in an unresolved augment, cannot evaluate */
3802 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node->parent,
3803 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
3804 return EXIT_FAILURE;
3805 }
3806
Radek Krejci3a5501d2016-07-18 22:03:34 +02003807 /* path is supposed to be evaluated in data tree, so we have to skip
3808 * all schema nodes that cannot be instantiated in data tree */
3809 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003810 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003811 node = lys_parent(node));
3812
Michal Vasko1f76a282015-08-04 16:16:53 +02003813 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003814 if (i == parent_times - 1) {
3815 /* top-level */
3816 break;
3817 }
3818
3819 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003820 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003821 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003822 }
3823 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003824 } else {
3825 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003826 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003827 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003828 }
3829
Michal Vaskobb520442017-05-23 10:55:18 +02003830 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3831 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003832 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003833get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003834 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02003835 }
3836
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003837 rc = lys_getnext_data(tmp_mod, (last_aug ? (struct lys_node *)last_aug : node), name, nam_len, LYS_LIST
Michal Vaskobb520442017-05-23 10:55:18 +02003838 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003839 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003840 if (last_aug) {
3841 goto get_next_augment;
3842 }
Michal Vasko1c007172017-03-10 10:20:44 +01003843 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003844 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003845 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003846
Michal Vaskoe27516a2016-10-10 17:55:31 +00003847 if (first_iter) {
3848 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003849 if (op_node && parent_times &&
3850 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003851 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003852 }
3853 first_iter = 0;
3854 }
3855
Michal Vasko1f76a282015-08-04 16:16:53 +02003856 if (has_predicate) {
3857 /* we have predicate, so the current result must be list */
3858 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003859 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003860 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003861 }
3862
Michal Vasko1c007172017-03-10 10:20:44 +01003863 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003864 if (!i) {
3865 return EXIT_FAILURE;
3866 } else if (i < 0) {
3867 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003868 }
3869 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003870 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003871 }
3872 } while (id[0]);
3873
Michal Vaskoca917682016-07-25 11:00:37 +02003874 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003875 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003876 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003877 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 +02003878 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003879 }
3880
Radek Krejcicf509982015-12-15 09:22:44 +01003881 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003882 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003883 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003884 return -1;
3885 }
3886
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003887 if (ret) {
3888 *ret = node;
3889 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003890
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003891 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003892}
3893
Michal Vasko730dfdf2015-08-11 14:48:05 +02003894/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003895 * @brief Resolve instance-identifier predicate in JSON data format.
3896 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003897 *
Michal Vasko1b6ca962017-08-03 14:23:09 +02003898 * @param[in] prev_mod Previous module to use in case there is no prefix.
Michal Vaskobb211122015-08-19 14:03:11 +02003899 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003900 * @param[in,out] node_match Nodes matching the restriction without
3901 * the predicate. Nodes not satisfying
3902 * the predicate are removed.
3903 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003904 * @return Number of characters successfully parsed,
3905 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003906 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003907static int
Michal Vasko1b6ca962017-08-03 14:23:09 +02003908resolve_instid_predicate(const struct lys_module *prev_mod, const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003909{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003910 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003911 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003912 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003913 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003914 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003915
Michal Vasko1f2cc332015-08-19 11:18:32 +02003916 assert(pred && node_match->count);
3917
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003918 idx = -1;
3919 parsed = 0;
3920
Michal Vaskob2f40be2016-09-08 16:03:48 +02003921 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003922 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003923 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003924 return -parsed+i;
3925 }
3926 parsed += i;
3927 pred += i;
3928
3929 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003930 /* pos */
3931 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003932 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003933 } else if (name[0] != '.') {
3934 /* list keys */
3935 if (pred_iter < 0) {
3936 pred_iter = 1;
3937 } else {
3938 ++pred_iter;
3939 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003940 }
3941
Michal Vaskof2f28a12016-09-09 12:43:06 +02003942 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003943 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003944 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003945 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003946 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003947 goto remove_instid;
3948 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003949
3950 target = node_match->node[j];
3951 /* check the value */
3952 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3953 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3954 goto remove_instid;
3955 }
3956
3957 } else if (!value) {
3958 /* keyless list position */
3959 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3960 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3961 goto remove_instid;
3962 }
3963
3964 if (idx != cur_idx) {
3965 goto remove_instid;
3966 }
3967
3968 } else {
3969 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003970 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003971 goto remove_instid;
3972 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003973
Michal Vaskob2f40be2016-09-08 16:03:48 +02003974 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003975 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003976 if (!target) {
3977 goto remove_instid;
3978 }
3979 if ((struct lys_node_leaf *)target->schema !=
3980 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3981 goto remove_instid;
3982 }
3983
Michal Vasko1b6ca962017-08-03 14:23:09 +02003984 /* check name */
3985 if (strncmp(target->schema->name, name, nam_len) || target->schema->name[nam_len]) {
3986 goto remove_instid;
3987 }
3988
3989 /* check module */
3990 if (model) {
3991 if (strncmp(target->schema->module->name, model, mod_len)
3992 || target->schema->module->name[mod_len]) {
3993 goto remove_instid;
3994 }
3995 } else {
3996 if (target->schema->module != prev_mod) {
3997 goto remove_instid;
3998 }
3999 }
4000
Michal Vaskob2f40be2016-09-08 16:03:48 +02004001 /* check the value */
4002 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
4003 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
4004 goto remove_instid;
4005 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004006 }
4007
Michal Vaskob2f40be2016-09-08 16:03:48 +02004008 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004009 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004010 continue;
4011
4012remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02004013 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02004014 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004015 }
4016 } while (has_predicate);
4017
Michal Vaskob2f40be2016-09-08 16:03:48 +02004018 /* check that all list keys were specified */
4019 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02004020 j = 0;
4021 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004022 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4023 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4024 /* not enough predicates, just remove the list instance */
4025 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004026 } else {
4027 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004028 }
4029 }
4030
4031 if (!node_match->count) {
4032 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4033 }
4034 }
4035
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036 return parsed;
4037}
4038
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004039int
Michal Vasko769f8032017-01-24 13:11:55 +01004040lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004041{
4042 struct lys_node *parent, *elem;
4043 struct lyxp_set set;
4044 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004045 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004046
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004047 if (check_place) {
4048 parent = node;
4049 while (parent) {
4050 if (parent->nodetype == LYS_GROUPING) {
4051 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004052 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004053 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004054 if (parent->nodetype == LYS_AUGMENT) {
4055 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004056 /* unresolved augment, skip for now (will be checked later) */
4057 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004058 } else {
4059 parent = ((struct lys_node_augment *)parent)->target;
4060 continue;
4061 }
4062 }
4063 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004064 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004065 }
4066
Michal Vasko769f8032017-01-24 13:11:55 +01004067 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4068 if (ret == -1) {
4069 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004070 }
4071
4072 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4073
4074 for (i = 0; i < set.used; ++i) {
4075 /* skip roots'n'stuff */
4076 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4077 /* XPath expression cannot reference "lower" status than the node that has the definition */
4078 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4079 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4080 return -1;
4081 }
4082
4083 if (parent) {
4084 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4085 if (!elem) {
4086 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004087 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004088 break;
4089 }
4090 }
4091 }
4092 }
4093
4094 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004095 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004096}
4097
Radek Krejcif71f48f2016-10-25 16:37:24 +02004098static int
4099check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4100{
4101 int i;
4102
4103 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004104 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4105 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004106 LOGVAL(LYE_SPEC, LY_VLOG_LYS, leaf, "The leafref %s is config but refers to a non-config %s.",
Radek Krejcif71f48f2016-10-25 16:37:24 +02004107 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4108 return -1;
4109 }
4110 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4111 * of leafref resolving (lys_leaf_add_leafref_target()) */
4112 } else if (type->base == LY_TYPE_UNION) {
4113 for (i = 0; i < type->info.uni.count; i++) {
4114 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4115 return -1;
4116 }
4117 }
4118 }
4119 return 0;
4120}
4121
Michal Vasko9e635ac2016-10-17 11:44:09 +02004122/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004123 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004124 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004125 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004126 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004127 * @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 +02004128 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004129 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004130 *
4131 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004132 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004133int
4134inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004135{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004136 struct lys_node_leaf *leaf;
4137
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004138 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004139 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004140 if (clear) {
4141 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004142 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004143 } else {
4144 if (node->flags & LYS_CONFIG_SET) {
4145 /* skip nodes with an explicit config value */
4146 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4147 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004148 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004149 return -1;
4150 }
4151 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004152 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004153
4154 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4155 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4156 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004157 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4158 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004159 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4160 return -1;
4161 }
4162 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004163 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004164 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004165 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004166 return -1;
4167 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004168 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4169 leaf = (struct lys_node_leaf *)node;
4170 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004171 return -1;
4172 }
4173 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004174 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004175
4176 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004177}
4178
Michal Vasko730dfdf2015-08-11 14:48:05 +02004179/**
Michal Vasko7178e692016-02-12 15:58:05 +01004180 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004181 *
Michal Vaskobb211122015-08-19 14:03:11 +02004182 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004183 * @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 +01004184 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004185 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004186 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004187 */
Michal Vasko7178e692016-02-12 15:58:05 +01004188static int
Radek Krejcib3142312016-11-09 11:04:12 +01004189resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004190{
Michal Vasko44ab1462017-05-18 13:18:36 +02004191 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004192 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004193 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004194 struct ly_set *set;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004195
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004196 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004197 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004198
Michal Vaskobb520442017-05-23 10:55:18 +02004199 /* set it as not applied for now */
4200 aug->flags |= LYS_NOTAPPLIED;
4201
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004202 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004203 if (!aug->target) {
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004204 /* resolve target node */
Michal Vasko50576712017-07-28 12:28:33 +02004205 rc = resolve_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : lys_node_module((struct lys_node *)aug)), &set, 0, 0);
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004206 if (rc == -1) {
Michal Vasko50576712017-07-28 12:28:33 +02004207 LOGVAL(LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004208 return -1;
4209 }
Michal Vasko50576712017-07-28 12:28:33 +02004210 if (!set) {
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004211 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4212 return EXIT_FAILURE;
4213 }
Michal Vasko50576712017-07-28 12:28:33 +02004214 aug->target = set->set.s[0];
4215 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004216 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004217
Michal Vaskod58d5962016-03-02 14:29:41 +01004218 /* check for mandatory nodes - if the target node is in another module
4219 * the added nodes cannot be mandatory
4220 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004221 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4222 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004223 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004224 }
4225
Michal Vasko07e89ef2016-03-03 13:28:57 +01004226 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004227 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004228 LY_TREE_FOR(aug->child, sub) {
4229 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4230 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4231 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4232 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004233 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004234 return -1;
4235 }
4236 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004237 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004238 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004239 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004240 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004241 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004242 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004243 return -1;
4244 }
4245 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004246 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004247 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004248 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004249 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004250 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004251 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004252 return -1;
4253 }
4254 }
4255 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004256 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004257 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004258 return -1;
4259 }
4260
Radek Krejcic071c542016-01-27 14:57:51 +01004261 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004262 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004263 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004264 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004265 }
4266 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004267
Michal Vasko44ab1462017-05-18 13:18:36 +02004268 if (!aug->child) {
4269 /* empty augment, nothing to connect, but it is techincally applied */
4270 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4271 aug->flags &= ~LYS_NOTAPPLIED;
4272 } else if (mod->implemented && apply_aug(aug, unres)) {
4273 /* we tried to connect it, we failed */
4274 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004275 }
4276
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004277 return EXIT_SUCCESS;
4278}
4279
Radek Krejcie534c132016-11-23 13:32:31 +01004280static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004281resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004282{
4283 enum LY_VLOG_ELEM vlog_type;
4284 void *vlog_node;
4285 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004286 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004287 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004288 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004289 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004290 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004291 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004292
4293 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004294 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004295 vlog_node = info->parent;
4296 vlog_type = LY_VLOG_LYS;
4297 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004298 case LYEXT_PAR_MODULE:
4299 case LYEXT_PAR_IMPORT:
4300 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004301 vlog_node = NULL;
4302 vlog_type = LY_VLOG_LYS;
4303 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004304 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004305 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004306 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004307 break;
4308 }
4309
4310 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004311 /* YIN */
4312
Radek Krejcie534c132016-11-23 13:32:31 +01004313 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004314 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004315 if (!mod) {
4316 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004317 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004318 }
4319
4320 /* find the extension definition */
4321 e = NULL;
4322 for (i = 0; i < mod->extensions_size; i++) {
4323 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4324 e = &mod->extensions[i];
4325 break;
4326 }
4327 }
4328 /* try submodules */
4329 for (j = 0; !e && j < mod->inc_size; j++) {
4330 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4331 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4332 e = &mod->inc[j].submodule->extensions[i];
4333 break;
4334 }
4335 }
4336 }
4337 if (!e) {
4338 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4339 return EXIT_FAILURE;
4340 }
4341
4342 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004343
Radek Krejci72b35992017-01-04 16:27:44 +01004344 if (e->plugin && e->plugin->check_position) {
4345 /* common part - we have plugin with position checking function, use it first */
4346 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4347 /* extension is not allowed here */
4348 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4349 return -1;
4350 }
4351 }
4352
Radek Krejci8d6b7422017-02-03 14:42:13 +01004353 /* extension type-specific part - allocation */
4354 if (e->plugin) {
4355 etype = e->plugin->type;
4356 } else {
4357 /* default type */
4358 etype = LYEXT_FLAG;
4359 }
4360 switch (etype) {
4361 case LYEXT_FLAG:
4362 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4363 break;
4364 case LYEXT_COMPLEX:
4365 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4366 break;
4367 case LYEXT_ERR:
4368 /* we never should be here */
4369 LOGINT;
4370 return -1;
4371 }
Radek Krejcia8d111f2017-05-31 13:57:37 +02004372 LY_CHECK_ERR_RETURN(!*ext, LOGMEM, -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004373
4374 /* common part for all extension types */
4375 (*ext)->def = e;
4376 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004377 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004378 (*ext)->insubstmt = info->substmt;
4379 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004380 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004381
4382 if (!(e->flags & LYS_YINELEM) && e->argument) {
4383 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4384 if (!(*ext)->arg_value) {
4385 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4386 return -1;
4387 }
4388 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4389 }
4390
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004391 (*ext)->nodetype = LYS_EXT;
4392 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004393
Radek Krejci8d6b7422017-02-03 14:42:13 +01004394 /* extension type-specific part - parsing content */
4395 switch (etype) {
4396 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004397 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4398 if (!yin->ns) {
4399 /* garbage */
4400 lyxml_free(mod->ctx, yin);
4401 continue;
4402 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4403 /* standard YANG statements are not expected here */
4404 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4405 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004406 } else if (yin->ns == info->data.yin->ns &&
4407 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004408 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004409 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004410 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004411 return -1;
4412 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004413 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004414 yin->content = NULL;
4415 lyxml_free(mod->ctx, yin);
4416 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004417 /* extension instance */
4418 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4419 LYEXT_SUBSTMT_SELF, 0, unres)) {
4420 return -1;
4421 }
Radek Krejci72b35992017-01-04 16:27:44 +01004422
Radek Krejci72b35992017-01-04 16:27:44 +01004423 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004424 }
Radek Krejci72b35992017-01-04 16:27:44 +01004425 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004426 break;
4427 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004428 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004429 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4430 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004431 return -1;
4432 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004433 break;
4434 default:
4435 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004436 }
Radek Krejci72b35992017-01-04 16:27:44 +01004437
4438 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4439
Radek Krejcie534c132016-11-23 13:32:31 +01004440 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004441 /* YANG */
4442
PavolVicanc1807262017-01-31 18:00:27 +01004443 ext_prefix = (char *)(*ext)->def;
4444 tmp = strchr(ext_prefix, ':');
4445 if (!tmp) {
4446 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004447 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004448 }
4449 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004450
PavolVicanc1807262017-01-31 18:00:27 +01004451 /* get the module where the extension is supposed to be defined */
4452 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4453 if (!mod) {
4454 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4455 return EXIT_FAILURE;
4456 }
4457
4458 /* find the extension definition */
4459 e = NULL;
4460 for (i = 0; i < mod->extensions_size; i++) {
4461 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4462 e = &mod->extensions[i];
4463 break;
4464 }
4465 }
4466 /* try submodules */
4467 for (j = 0; !e && j < mod->inc_size; j++) {
4468 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4469 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4470 e = &mod->inc[j].submodule->extensions[i];
4471 break;
4472 }
4473 }
4474 }
4475 if (!e) {
4476 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4477 return EXIT_FAILURE;
4478 }
4479
4480 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4481
4482 if (e->plugin && e->plugin->check_position) {
4483 /* common part - we have plugin with position checking function, use it first */
4484 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4485 /* extension is not allowed here */
4486 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004487 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004488 }
4489 }
4490
PavolVican22e88682017-02-14 22:38:18 +01004491 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004492 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004493 (*ext)->def = e;
4494 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004495 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004496
PavolVicanb0d84102017-02-15 16:32:42 +01004497 if (e->argument && !(*ext)->arg_value) {
4498 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4499 goto error;
4500 }
4501
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004502 (*ext)->module = info->mod;
4503 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004504
PavolVican22e88682017-02-14 22:38:18 +01004505 /* extension type-specific part */
4506 if (e->plugin) {
4507 etype = e->plugin->type;
4508 } else {
4509 /* default type */
4510 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004511 }
PavolVican22e88682017-02-14 22:38:18 +01004512 switch (etype) {
4513 case LYEXT_FLAG:
4514 /* nothing change */
4515 break;
4516 case LYEXT_COMPLEX:
4517 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004518 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM, error);
PavolVican22e88682017-02-14 22:38:18 +01004519 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4520 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004521 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004522 if (info->data.yang) {
4523 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004524 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4525 (struct lys_ext_instance_complex*)(*ext))) {
4526 goto error;
4527 }
4528 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4529 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004530 goto error;
4531 }
PavolVicana3876672017-02-21 15:49:51 +01004532 }
4533 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4534 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004535 }
PavolVican22e88682017-02-14 22:38:18 +01004536 break;
4537 case LYEXT_ERR:
4538 /* we never should be here */
4539 LOGINT;
4540 goto error;
4541 }
4542
PavolVican22e88682017-02-14 22:38:18 +01004543 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4544 goto error;
4545 }
4546 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004547 }
4548
4549 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004550error:
4551 free(ext_prefix);
4552 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004553}
4554
Michal Vasko730dfdf2015-08-11 14:48:05 +02004555/**
Pavol Vican855ca622016-09-05 13:07:54 +02004556 * @brief Resolve (find) choice default case. Does not log.
4557 *
4558 * @param[in] choic Choice to use.
4559 * @param[in] dflt Name of the default case.
4560 *
4561 * @return Pointer to the default node or NULL.
4562 */
4563static struct lys_node *
4564resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4565{
4566 struct lys_node *child, *ret;
4567
4568 LY_TREE_FOR(choic->child, child) {
4569 if (child->nodetype == LYS_USES) {
4570 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4571 if (ret) {
4572 return ret;
4573 }
4574 }
4575
4576 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004577 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004578 return child;
4579 }
4580 }
4581
4582 return NULL;
4583}
4584
4585/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004586 * @brief Resolve uses, apply augments, refines. Logs directly.
4587 *
Michal Vaskobb211122015-08-19 14:03:11 +02004588 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004589 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004590 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004591 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004592 */
Michal Vasko184521f2015-09-24 13:14:26 +02004593static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004594resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004595{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004596 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004597 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004598 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004599 struct lys_node_leaflist *llist;
4600 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004601 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004602 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004603 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004604 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004605 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004606 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004607
Michal Vasko71e1aa82015-08-12 12:17:51 +02004608 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004609
Radek Krejci93def382017-05-24 15:33:48 +02004610 /* check that the grouping is resolved (no unresolved uses inside) */
4611 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004612
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004613 if (!uses->grp->child) {
4614 /* grouping without children, warning was already displayed */
4615 return EXIT_SUCCESS;
4616 }
4617
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004618 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004619 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004620 if (node_aux->nodetype & LYS_GROUPING) {
4621 /* do not instantiate groupings from groupings */
4622 continue;
4623 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004624 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004625 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004626 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004627 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004628 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004629 }
Pavol Vican55abd332016-07-12 15:54:49 +02004630 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004631 LY_TREE_FOR((uses->parent) ? *lys_child(uses->parent, LYS_USES) : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004632 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004633 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004634 }
4635 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004636 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004637
Michal Vaskodef0db12015-10-07 13:22:48 +02004638 /* we managed to copy the grouping, the rest must be possible to resolve */
4639
Pavol Vican855ca622016-09-05 13:07:54 +02004640 if (uses->refine_size) {
4641 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004642 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004643 }
4644
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004645 /* apply refines */
4646 for (i = 0; i < uses->refine_size; i++) {
4647 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004648 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4649 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004650 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004651 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004652 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004653 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004654 }
4655
Radek Krejci1d82ef62015-08-07 14:44:40 +02004656 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004657 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004658 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004659 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004660 }
Pavol Vican855ca622016-09-05 13:07:54 +02004661 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004662
4663 /* description on any nodetype */
4664 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004665 lydict_remove(ctx, node->dsc);
4666 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004667 }
4668
4669 /* reference on any nodetype */
4670 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004671 lydict_remove(ctx, node->ref);
4672 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004673 }
4674
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004675 /* config on any nodetype,
4676 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4677 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004678 node->flags &= ~LYS_CONFIG_MASK;
4679 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004680 }
4681
4682 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004683 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004684 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004685 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004686 leaf = (struct lys_node_leaf *)node;
4687
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004688 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004689 lydict_remove(ctx, leaf->dflt);
4690 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4691
4692 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004693 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4694 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004695 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004696 }
Radek Krejci200bf712016-08-16 17:11:04 +02004697 } else if (node->nodetype == LYS_LEAFLIST) {
4698 /* leaf-list */
4699 llist = (struct lys_node_leaflist *)node;
4700
4701 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004702 for (j = 0; j < llist->dflt_size; j++) {
4703 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004704 }
4705 free(llist->dflt);
4706
4707 /* copy the default set from refine */
Radek Krejcia8d111f2017-05-31 13:57:37 +02004708 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
4709 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM, fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004710 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004711 for (j = 0; j < llist->dflt_size; j++) {
4712 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004713 }
4714
4715 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004716 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004717 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004718 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004719 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004720 }
4721 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004722 }
4723 }
4724
4725 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004726 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004727 /* remove current value */
4728 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004729
Radek Krejcibf285832017-01-26 16:05:41 +01004730 /* set new value */
4731 node->flags |= (rfn->flags & LYS_MAND_MASK);
4732
Pavol Vican855ca622016-09-05 13:07:54 +02004733 if (rfn->flags & LYS_MAND_TRUE) {
4734 /* check if node has default value */
4735 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004736 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4737 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004738 goto fail;
4739 }
4740 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004741 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4742 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004743 goto fail;
4744 }
4745 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004746 }
4747
4748 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004749 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4750 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4751 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004752 }
4753
4754 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004755 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004756 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004757 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004758 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004759 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004760 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004761 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004762 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004763 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004764 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004765 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004766 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004767 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004768 }
4769 }
4770
4771 /* must in leaf, leaf-list, list, container or anyxml */
4772 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004773 switch (node->nodetype) {
4774 case LYS_LEAF:
4775 old_size = &((struct lys_node_leaf *)node)->must_size;
4776 old_must = &((struct lys_node_leaf *)node)->must;
4777 break;
4778 case LYS_LEAFLIST:
4779 old_size = &((struct lys_node_leaflist *)node)->must_size;
4780 old_must = &((struct lys_node_leaflist *)node)->must;
4781 break;
4782 case LYS_LIST:
4783 old_size = &((struct lys_node_list *)node)->must_size;
4784 old_must = &((struct lys_node_list *)node)->must;
4785 break;
4786 case LYS_CONTAINER:
4787 old_size = &((struct lys_node_container *)node)->must_size;
4788 old_must = &((struct lys_node_container *)node)->must;
4789 break;
4790 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004791 case LYS_ANYDATA:
4792 old_size = &((struct lys_node_anydata *)node)->must_size;
4793 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004794 break;
4795 default:
4796 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004797 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004798 }
4799
4800 size = *old_size + rfn->must_size;
4801 must = realloc(*old_must, size * sizeof *rfn->must);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004802 LY_CHECK_ERR_GOTO(!must, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004803 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004804 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004805 lys_ext_dup(rfn->module, rfn->must[k].ext, rfn->must[k].ext_size, &rfn->must[k], LYEXT_PAR_RESTR,
Radek Krejci5138e9f2017-04-12 13:10:46 +02004806 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004807 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4808 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4809 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4810 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4811 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004812 }
4813
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004814 *old_must = must;
4815 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004816
4817 /* check XPath dependencies again */
4818 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4819 goto fail;
4820 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004821 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004822
4823 /* if-feature in leaf, leaf-list, list, container or anyxml */
4824 if (rfn->iffeature_size) {
4825 old_size = &node->iffeature_size;
4826 old_iff = &node->iffeature;
4827
4828 size = *old_size + rfn->iffeature_size;
4829 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004830 LY_CHECK_ERR_GOTO(!iff, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004831 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4832 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004833 if (usize1) {
4834 /* there is something to duplicate */
4835 /* duplicate compiled expression */
4836 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4837 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004838 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004839 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004840
4841 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004842 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004843 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004844 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004845 }
4846 }
4847
4848 *old_iff = iff;
4849 *old_size = size;
4850 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004851 }
4852
4853 /* apply augments */
4854 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004855 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004856 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004857 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004858 }
4859 }
4860
Pavol Vican855ca622016-09-05 13:07:54 +02004861 /* check refines */
4862 for (i = 0; i < uses->refine_size; i++) {
4863 node = refine_nodes[i];
4864 rfn = &uses->refine[i];
4865
4866 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004867 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004868 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004869 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004870 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4871 (rfn->flags & LYS_CONFIG_W)) {
4872 /* setting config true under config false is prohibited */
4873 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004874 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004875 "changing config from 'false' to 'true' is prohibited while "
4876 "the target's parent is still config 'false'.");
4877 goto fail;
4878 }
4879
4880 /* inherit config change to the target children */
4881 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4882 if (rfn->flags & LYS_CONFIG_W) {
4883 if (iter->flags & LYS_CONFIG_SET) {
4884 /* config is set explicitely, go to next sibling */
4885 next = NULL;
4886 goto nextsibling;
4887 }
4888 } else { /* LYS_CONFIG_R */
4889 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4890 /* error - we would have config data under status data */
4891 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004892 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004893 "changing config from 'true' to 'false' is prohibited while the target "
4894 "has still a children with explicit config 'true'.");
4895 goto fail;
4896 }
4897 }
4898 /* change config */
4899 iter->flags &= ~LYS_CONFIG_MASK;
4900 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4901
4902 /* select next iter - modified LY_TREE_DFS_END */
4903 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4904 next = NULL;
4905 } else {
4906 next = iter->child;
4907 }
4908nextsibling:
4909 if (!next) {
4910 /* try siblings */
4911 next = iter->next;
4912 }
4913 while (!next) {
4914 /* parent is already processed, go to its sibling */
4915 iter = lys_parent(iter);
4916
4917 /* no siblings, go back through parents */
4918 if (iter == node) {
4919 /* we are done, no next element to process */
4920 break;
4921 }
4922 next = iter->next;
4923 }
4924 }
4925 }
4926
4927 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004928 if (rfn->dflt_size) {
4929 if (node->nodetype == LYS_CHOICE) {
4930 /* choice */
4931 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4932 rfn->dflt[0]);
4933 if (!((struct lys_node_choice *)node)->dflt) {
4934 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4935 goto fail;
4936 }
4937 if (lyp_check_mandatory_choice(node)) {
4938 goto fail;
4939 }
Pavol Vican855ca622016-09-05 13:07:54 +02004940 }
4941 }
4942
4943 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02004944 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004945 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004946 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4947 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004948 goto fail;
4949 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02004950 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004951 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004952 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4953 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004954 goto fail;
4955 }
4956 }
4957
4958 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004959 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004960 if (node->nodetype == LYS_LEAFLIST) {
4961 llist = (struct lys_node_leaflist *)node;
4962 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004963 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
4964 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004965 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4966 goto fail;
4967 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004968 } else if (node->nodetype == LYS_LEAF) {
4969 leaf = (struct lys_node_leaf *)node;
4970 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004971 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
4972 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004973 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4974 goto fail;
4975 }
Pavol Vican855ca622016-09-05 13:07:54 +02004976 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004977
Pavol Vican855ca622016-09-05 13:07:54 +02004978 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004979 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004980 for (parent = node->parent;
4981 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4982 parent = parent->parent) {
4983 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4984 /* stop also on presence containers */
4985 break;
4986 }
4987 }
4988 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4989 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4990 if (lyp_check_mandatory_choice(parent)) {
4991 goto fail;
4992 }
4993 }
4994 }
4995 }
4996 free(refine_nodes);
4997
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004998 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004999
5000fail:
5001 LY_TREE_FOR_SAFE(uses->child, next, iter) {
5002 lys_node_free(iter, NULL, 0);
5003 }
Pavol Vican855ca622016-09-05 13:07:54 +02005004 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02005005 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005006}
5007
Radek Krejci83a4bac2017-02-07 15:53:04 +01005008void
5009resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02005010{
5011 int i;
5012
5013 assert(der && base);
5014
Radek Krejci018f1f52016-08-03 16:01:20 +02005015 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005016 /* create a set for backlinks if it does not exist */
5017 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02005018 }
Radek Krejci85a54be2016-10-20 12:39:56 +02005019 /* store backlink */
5020 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005021
Radek Krejci85a54be2016-10-20 12:39:56 +02005022 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005023 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005024 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005025 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005026}
5027
Michal Vasko730dfdf2015-08-11 14:48:05 +02005028/**
5029 * @brief Resolve base identity recursively. Does not log.
5030 *
5031 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005032 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005033 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005034 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005035 *
Radek Krejci219fa612016-08-15 10:36:51 +02005036 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005037 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005038static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005039resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005040 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005041{
Michal Vaskof02e3742015-08-05 16:27:02 +02005042 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005043 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005044
Radek Krejcicf509982015-12-15 09:22:44 +01005045 assert(ret);
5046
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005047 /* search module */
5048 for (i = 0; i < module->ident_size; i++) {
5049 if (!strcmp(basename, module->ident[i].name)) {
5050
5051 if (!ident) {
5052 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005053 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005054 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005055 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005056 }
5057
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005058 base = &module->ident[i];
5059 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005060 }
5061 }
5062
5063 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005064 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5065 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5066 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005067
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005068 if (!ident) {
5069 *ret = &module->inc[j].submodule->ident[i];
5070 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005071 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005072
5073 base = &module->inc[j].submodule->ident[i];
5074 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005075 }
5076 }
5077 }
5078
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005079matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005080 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005081 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005082 /* is it already completely resolved? */
5083 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005084 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005085 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5086
5087 /* simple check for circular reference,
5088 * the complete check is done as a side effect of using only completely
5089 * resolved identities (previous check of unres content) */
5090 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5091 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5092 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005093 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005094 }
5095
Radek Krejci06f64ed2016-08-15 11:07:44 +02005096 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005097 }
5098 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005099
Radek Krejcibabbff82016-02-19 13:31:37 +01005100 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005101 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005102 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005103 }
5104
Radek Krejci219fa612016-08-15 10:36:51 +02005105 /* base not found (maybe a forward reference) */
5106 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005107}
5108
Michal Vasko730dfdf2015-08-11 14:48:05 +02005109/**
5110 * @brief Resolve base identity. Logs directly.
5111 *
5112 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005113 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005114 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005115 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005116 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005117 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005118 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005119 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005120static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005121resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005122 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005123{
5124 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005125 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005126 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005127 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005128 struct lys_module *mod;
5129
5130 assert((ident && !type) || (!ident && type));
5131
5132 if (!type) {
5133 /* have ident to resolve */
5134 ret = &target;
5135 flags = ident->flags;
5136 mod = ident->module;
5137 } else {
5138 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005139 ++type->info.ident.count;
5140 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
Radek Krejcia8d111f2017-05-31 13:57:37 +02005141 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM, -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005142
5143 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005144 flags = type->parent->flags;
5145 mod = type->parent->module;
5146 }
Michal Vaskof2006002016-04-21 16:28:15 +02005147 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005148
5149 /* search for the base identity */
5150 name = strchr(basename, ':');
5151 if (name) {
5152 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005153 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005154 name++;
5155
Michal Vasko2d851a92015-10-20 16:16:36 +02005156 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005157 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005158 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005159 }
5160 } else {
5161 name = basename;
5162 }
5163
Radek Krejcic071c542016-01-27 14:57:51 +01005164 /* get module where to search */
5165 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5166 if (!module) {
5167 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005168 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005169 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005170 }
5171
Radek Krejcic071c542016-01-27 14:57:51 +01005172 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005173 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5174 if (!rc) {
5175 assert(*ret);
5176
5177 /* check status */
5178 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5179 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5180 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005181 } else if (ident) {
5182 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005183 if (lys_main_module(mod)->implemented) {
5184 /* in case of the implemented identity, maintain backlinks to it
5185 * from the base identities to make it available when resolving
5186 * data with the identity values (not implemented identity is not
5187 * allowed as an identityref value). */
5188 resolve_identity_backlink_update(ident, *ret);
5189 }
Radek Krejci219fa612016-08-15 10:36:51 +02005190 }
5191 } else if (rc == EXIT_FAILURE) {
5192 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005193 if (type) {
5194 --type->info.ident.count;
5195 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005196 }
5197
Radek Krejci219fa612016-08-15 10:36:51 +02005198 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005199}
5200
Radek Krejci9e6af732017-04-27 14:40:25 +02005201/*
5202 * 1 - true (der is derived from base)
5203 * 0 - false (der is not derived from base)
5204 */
5205static int
5206search_base_identity(struct lys_ident *der, struct lys_ident *base)
5207{
5208 int i;
5209
5210 if (der == base) {
5211 return 1;
5212 } else {
5213 for(i = 0; i < der->base_size; i++) {
5214 if (search_base_identity(der->base[i], base) == 1) {
5215 return 1;
5216 }
5217 }
5218 }
5219
5220 return 0;
5221}
5222
Michal Vasko730dfdf2015-08-11 14:48:05 +02005223/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005224 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005225 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005226 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005227 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005228 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005229 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005230 *
5231 * @return Pointer to the identity resolvent, NULL on error.
5232 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005233struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005234resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node, struct lys_module *mod, int dflt)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005235{
Radek Krejci9e6af732017-04-27 14:40:25 +02005236 const char *mod_name, *name;
Michal Vasko50576712017-07-28 12:28:33 +02005237 int mod_name_len, nam_len, rc, i, j;
Radek Krejci9e6af732017-04-27 14:40:25 +02005238 int make_implemented = 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02005239 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005240 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005241 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005242
Radek Krejci9e6af732017-04-27 14:40:25 +02005243 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005244
Michal Vaskof2d43962016-09-02 11:10:16 +02005245 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005246 return NULL;
5247 }
5248
Michal Vasko50576712017-07-28 12:28:33 +02005249 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005250 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005251 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005252 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005253 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005254 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005255 return NULL;
5256 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005257
5258 m = lys_main_module(mod); /* shortcut */
5259 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5260 /* identity is defined in the same module as node */
5261 imod = m;
5262 } else if (dflt) {
5263 /* solving identityref in default definition in schema -
5264 * find the identity's module in the imported modules list to have a correct revision */
5265 for (i = 0; i < mod->imp_size; i++) {
5266 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5267 imod = mod->imp[i].module;
5268 break;
5269 }
5270 }
5271 } else {
5272 /* solving identityref in data - get the (implemented) module from the context */
5273 u = 0;
5274 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5275 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5276 break;
5277 }
5278 }
5279 }
5280 if (!imod) {
5281 goto fail;
5282 }
5283
5284 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5285 /* we are solving default statement in schema AND the type is not referencing the same schema,
5286 * THEN, we may need to make the module with the identity implemented, but only if it really
5287 * contains the identity */
5288 if (!imod->implemented) {
5289 cur = NULL;
5290 /* get the identity in the module */
5291 for (i = 0; i < imod->ident_size; i++) {
5292 if (!strcmp(name, imod->ident[i].name)) {
5293 cur = &imod->ident[i];
5294 break;
5295 }
5296 }
5297 if (!cur) {
5298 /* go through includes */
5299 for (j = 0; j < imod->inc_size; j++) {
5300 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5301 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5302 cur = &imod->inc[j].submodule->ident[i];
5303 break;
5304 }
5305 }
5306 }
5307 if (!cur) {
5308 goto fail;
5309 }
5310 }
5311
5312 /* check that identity is derived from one of the type's base */
5313 while (type->der) {
5314 for (i = 0; i < type->info.ident.count; i++) {
5315 if (search_base_identity(cur, type->info.ident.ref[i])) {
5316 /* cur's base matches the type's base */
5317 make_implemented = 1;
5318 goto match;
5319 }
5320 }
5321 type = &type->der->type;
5322 }
5323 /* matching base not found */
5324 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5325 goto fail;
5326 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005327 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005328
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005329 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005330 while (type->der) {
5331 for (i = 0; i < type->info.ident.count; ++i) {
5332 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005333
Radek Krejci85a54be2016-10-20 12:39:56 +02005334 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005335 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005336 for (u = 0; u < cur->der->number; u++) {
5337 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005338 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005339 /* we have match */
5340 cur = der;
5341 goto match;
5342 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005343 }
5344 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005345 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005346 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005347 }
5348
Radek Krejci9e6af732017-04-27 14:40:25 +02005349fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005350 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005351 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005352
5353match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005354 for (i = 0; i < cur->iffeature_size; i++) {
5355 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005356 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005357 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 +02005358 return NULL;
5359 }
5360 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005361 if (make_implemented) {
5362 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5363 imod->name, cur->name, mod->name);
5364 if (lys_set_implemented(imod)) {
5365 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5366 imod->name, cur->name);
5367 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5368 goto fail;
5369 }
5370 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005371 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005372}
5373
Michal Vasko730dfdf2015-08-11 14:48:05 +02005374/**
Michal Vaskobb211122015-08-19 14:03:11 +02005375 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005376 *
Michal Vaskobb211122015-08-19 14:03:11 +02005377 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005378 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005379 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005380 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005381 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005382static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005383resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005384{
Radek Krejci93def382017-05-24 15:33:48 +02005385 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005386 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005387
Radek Krejci6ff885d2017-01-03 14:06:22 +01005388 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself is used
Radek Krejci93def382017-05-24 15:33:48 +02005389 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5390 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5391 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005392 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 +02005393
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005394 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005395 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5396 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005397 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005398 return -1;
5399 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005400 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005401 return -1;
5402 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005403 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005404 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5405 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5406 return -1;
5407 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005408 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005409 }
Michal Vasko92981a62016-10-14 10:25:16 +02005410 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005411 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005412 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005413 }
5414
Radek Krejci93def382017-05-24 15:33:48 +02005415 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005416 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005417 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5418 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5419 return -1;
5420 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005421 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005422 } else {
5423 /* instantiate grouping only when it is completely resolved */
5424 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005425 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005426 return EXIT_FAILURE;
5427 }
5428
Radek Krejci48464ed2016-03-17 15:44:09 +01005429 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005430 if (!rc) {
5431 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005432 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005433 assert(((struct lys_node_grp *)par_grp)->unres_count);
5434 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005435 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005436 }
Radek Krejcicf509982015-12-15 09:22:44 +01005437
5438 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005439 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005440 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005441 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005442 return -1;
5443 }
5444
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005445 return EXIT_SUCCESS;
5446 }
5447
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005448 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005449}
5450
Michal Vasko730dfdf2015-08-11 14:48:05 +02005451/**
Michal Vasko9957e592015-08-17 15:04:09 +02005452 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005453 *
Michal Vaskobb211122015-08-19 14:03:11 +02005454 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005455 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005456 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005457 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005458 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005459static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005460resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005461{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005462 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005463 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005464 char *s = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005465
5466 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005467 assert(keys_str);
5468
Radek Krejci5c08a992016-11-02 13:30:04 +01005469 if (!list->child) {
5470 /* no child, possible forward reference */
5471 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5472 return EXIT_FAILURE;
5473 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005474 /* get the key name */
5475 if ((value = strpbrk(keys_str, " \t\n"))) {
5476 len = value - keys_str;
5477 while (isspace(value[0])) {
5478 value++;
5479 }
5480 } else {
5481 len = strlen(keys_str);
5482 }
5483
Radek Krejcia98048c2017-05-24 16:35:48 +02005484 if (list->keys[i]) {
5485 /* skip already resolved keys */
5486 goto next;
5487 }
5488
Michal Vaskobb520442017-05-23 10:55:18 +02005489 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5490 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005491 if (rc) {
Radek Krejcia98048c2017-05-24 16:35:48 +02005492 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005493 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005494 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005495
Radek Krejci48464ed2016-03-17 15:44:09 +01005496 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005497 /* check_key logs */
5498 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005499 }
5500
Radek Krejcicf509982015-12-15 09:22:44 +01005501 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005502 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005503 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5504 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005505 return -1;
5506 }
5507
Radek Krejcia98048c2017-05-24 16:35:48 +02005508 /* default value - is ignored, keep it but print a warning */
5509 if (list->keys[i]->dflt) {
5510 /* log is not hidden only in case this resolving fails and in such a case
5511 * we cannot get here
5512 */
5513 assert(*ly_vlog_hide_location());
5514 ly_vlog_hide(0);
5515 LOGWRN("Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
5516 list->keys[i]->name, s = lys_path((struct lys_node*)list));
5517 ly_vlog_hide(1);
5518 free(s);
5519 }
5520
5521next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005522 /* prepare for next iteration */
5523 while (value && isspace(value[0])) {
5524 value++;
5525 }
5526 keys_str = value;
5527 }
5528
Michal Vaskof02e3742015-08-05 16:27:02 +02005529 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005530}
5531
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005532/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005533 * @brief Resolve (check) all must conditions of \p node.
5534 * Logs directly.
5535 *
5536 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005537 * @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 +02005538 *
5539 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5540 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005541static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005542resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005543{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005544 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005545 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005546 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005547 struct lys_restr *must;
5548 struct lyxp_set set;
5549
5550 assert(node);
5551 memset(&set, 0, sizeof set);
5552
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005553 if (inout_parent) {
5554 for (schema = lys_parent(node->schema);
5555 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5556 schema = lys_parent(schema));
5557 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5558 LOGINT;
5559 return -1;
5560 }
5561 must_size = ((struct lys_node_inout *)schema)->must_size;
5562 must = ((struct lys_node_inout *)schema)->must;
5563
Michal Vasko3cfa3182017-01-17 10:00:58 +01005564 node_flags = schema->flags;
5565
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005566 /* context node is the RPC/action */
5567 node = node->parent;
5568 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5569 LOGINT;
5570 return -1;
5571 }
5572 } else {
5573 switch (node->schema->nodetype) {
5574 case LYS_CONTAINER:
5575 must_size = ((struct lys_node_container *)node->schema)->must_size;
5576 must = ((struct lys_node_container *)node->schema)->must;
5577 break;
5578 case LYS_LEAF:
5579 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5580 must = ((struct lys_node_leaf *)node->schema)->must;
5581 break;
5582 case LYS_LEAFLIST:
5583 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5584 must = ((struct lys_node_leaflist *)node->schema)->must;
5585 break;
5586 case LYS_LIST:
5587 must_size = ((struct lys_node_list *)node->schema)->must_size;
5588 must = ((struct lys_node_list *)node->schema)->must;
5589 break;
5590 case LYS_ANYXML:
5591 case LYS_ANYDATA:
5592 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5593 must = ((struct lys_node_anydata *)node->schema)->must;
5594 break;
5595 case LYS_NOTIF:
5596 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5597 must = ((struct lys_node_notif *)node->schema)->must;
5598 break;
5599 default:
5600 must_size = 0;
5601 break;
5602 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005603
5604 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005605 }
5606
5607 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005608 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005609 return -1;
5610 }
5611
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005612 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005613
Michal Vasko8146d4c2016-05-09 15:50:29 +02005614 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005615 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005616 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5617 } else {
5618 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5619 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005620 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005621 }
5622 if (must[i].eapptag) {
5623 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5624 }
5625 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005626 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005627 }
5628 }
5629
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005630 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005631}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005632
Michal Vaskobf19d252015-10-08 15:39:17 +02005633/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005634 * @brief Resolve (find) when condition schema context node. Does not log.
5635 *
5636 * @param[in] schema Schema node with the when condition.
5637 * @param[out] ctx_snode When schema context node.
5638 * @param[out] ctx_snode_type Schema context node type.
5639 */
5640void
5641resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5642{
5643 const struct lys_node *sparent;
5644
5645 /* find a not schema-only node */
5646 *ctx_snode_type = LYXP_NODE_ELEM;
5647 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5648 if (schema->nodetype == LYS_AUGMENT) {
5649 sparent = ((struct lys_node_augment *)schema)->target;
5650 } else {
5651 sparent = schema->parent;
5652 }
5653 if (!sparent) {
5654 /* context node is the document root (fake root in our case) */
5655 if (schema->flags & LYS_CONFIG_W) {
5656 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5657 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005658 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005659 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005660 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005661 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005662 break;
5663 }
5664 schema = sparent;
5665 }
5666
5667 *ctx_snode = (struct lys_node *)schema;
5668}
5669
5670/**
Michal Vaskocf024702015-10-08 15:01:42 +02005671 * @brief Resolve (find) when condition context node. Does not log.
5672 *
5673 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005674 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005675 * @param[out] ctx_node Context node.
5676 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005677 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005678 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005679 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005680static int
5681resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5682 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005683{
Michal Vaskocf024702015-10-08 15:01:42 +02005684 struct lyd_node *parent;
5685 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005686 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005687 uint16_t i, data_depth, schema_depth;
5688
Michal Vasko508a50d2016-09-07 14:50:33 +02005689 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005690
Michal Vaskofe989752016-09-08 08:47:26 +02005691 if (node_type == LYXP_NODE_ELEM) {
5692 /* standard element context node */
5693 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5694 for (sparent = schema, schema_depth = 0;
5695 sparent;
5696 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5697 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5698 ++schema_depth;
5699 }
Michal Vaskocf024702015-10-08 15:01:42 +02005700 }
Michal Vaskofe989752016-09-08 08:47:26 +02005701 if (data_depth < schema_depth) {
5702 return -1;
5703 }
Michal Vaskocf024702015-10-08 15:01:42 +02005704
Michal Vasko956e8542016-08-26 09:43:35 +02005705 /* find the corresponding data node */
5706 for (i = 0; i < data_depth - schema_depth; ++i) {
5707 node = node->parent;
5708 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005709 if (node->schema != schema) {
5710 return -1;
5711 }
Michal Vaskofe989752016-09-08 08:47:26 +02005712 } else {
5713 /* root context node */
5714 while (node->parent) {
5715 node = node->parent;
5716 }
5717 while (node->prev->next) {
5718 node = node->prev;
5719 }
Michal Vaskocf024702015-10-08 15:01:42 +02005720 }
5721
Michal Vaskoa59495d2016-08-22 09:18:58 +02005722 *ctx_node = node;
5723 *ctx_node_type = node_type;
5724 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005725}
5726
Michal Vasko76c3bd32016-08-24 16:02:52 +02005727/**
5728 * @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 +01005729 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005730 *
5731 * @param[in] snode Schema node, whose children instances need to be unlinked.
5732 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5733 * it is moved to point to another sibling still in the original tree.
5734 * @param[in,out] ctx_node When context node, adjusted if needed.
5735 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5736 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5737 * Ordering may change, but there will be no semantic change.
5738 *
5739 * @return EXIT_SUCCESS on success, -1 on error.
5740 */
5741static int
5742resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5743 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5744{
5745 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005746 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005747
5748 switch (snode->nodetype) {
5749 case LYS_AUGMENT:
5750 case LYS_USES:
5751 case LYS_CHOICE:
5752 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005753 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005754 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005755 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5756 continue;
5757 }
5758
5759 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005760 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 */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005807 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005808 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 Vasko2bce30c2017-02-06 12:16:39 +01005849 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005850 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005851 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005852 return -1;
5853 }
5854 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005855 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005856 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
Michal Vasko78d97e22017-02-21 09:54:38 +01005983 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((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) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006054 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006055 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6056 ((struct lys_node_uses *)sparent)->when->cond);
6057 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006058 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006059 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) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006156 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006157 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 */
Radek Krejciecda01a2017-04-05 15:44:27 +02006163 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006164 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 Vaskoc5c55ca2017-06-30 13:15:18 +02006226static int
6227check_type_union_leafref(struct lys_type *type)
6228{
6229 uint8_t i;
6230
6231 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6232 /* go through unions and look for leafref */
6233 for (i = 0; i < type->info.uni.count; ++i) {
6234 switch (type->info.uni.types[i].base) {
6235 case LY_TYPE_LEAFREF:
6236 return 1;
6237 case LY_TYPE_UNION:
6238 if (check_type_union_leafref(&type->info.uni.types[i])) {
6239 return 1;
6240 }
6241 break;
6242 default:
6243 break;
6244 }
6245 }
6246
6247 return 0;
6248 }
6249
6250 /* just inherit the flag value */
6251 return type->der->has_union_leafref;
6252}
6253
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006254/**
Michal Vaskobb211122015-08-19 14:03:11 +02006255 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006256 *
6257 * @param[in] mod Main module.
6258 * @param[in] item Item to resolve. Type determined by \p type.
6259 * @param[in] type Type of the unresolved item.
6260 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006261 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006262 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006263 *
6264 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6265 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006266static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006267resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006268 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006269{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006270 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006271 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006272 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006273 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006274 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006275 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006276
Radek Krejcic79c6b12016-07-26 15:11:49 +02006277 struct ly_set *refs, *procs;
6278 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006279 struct lys_ident *ident;
6280 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006281 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006282 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006283 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006284 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006285 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006286 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006287 struct lys_ext_instance *ext, **extlist;
6288 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006289
6290 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006291 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006292 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006293 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006294 ident = item;
6295
Radek Krejci018f1f52016-08-03 16:01:20 +02006296 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006297 break;
6298 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006299 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006300 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006301 stype = item;
6302
Radek Krejci018f1f52016-08-03 16:01:20 +02006303 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006304 break;
6305 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006306 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006307 stype = item;
6308
Michal Vasko1c007172017-03-10 10:20:44 +01006309 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6310 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006311 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006312 /* check if leafref and its target are under a common if-features */
6313 rc = check_leafref_features(stype);
6314 if (rc) {
6315 break;
6316 }
6317
Michal Vaskobb520442017-05-23 10:55:18 +02006318 if (lys_node_module(node)->implemented) {
6319 /* make all the modules on the path implemented */
6320 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6321 if (!lys_node_module(next)->implemented) {
6322 if (lys_set_implemented(lys_node_module(next))) {
6323 rc = -1;
6324 break;
6325 }
6326 }
6327 }
6328 if (next) {
6329 break;
6330 }
6331
6332 /* store the backlink from leafref target */
6333 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6334 rc = -1;
6335 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006336 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006337 }
6338
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006339 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006340 case UNRES_TYPE_DER_EXT:
6341 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006342 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006343 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006344 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006345 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006346 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006347 /* parent */
6348 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006349 stype = item;
6350
Michal Vasko88c29542015-11-27 14:57:53 +01006351 /* HACK type->der is temporarily unparsed type statement */
6352 yin = (struct lyxml_elem *)stype->der;
6353 stype->der = NULL;
6354
Pavol Vicana0e4e672016-02-24 12:20:04 +01006355 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6356 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006357 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006358
6359 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006360 /* may try again later */
6361 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006362 } else {
6363 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006364 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006365 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006366 }
6367
Michal Vasko88c29542015-11-27 14:57:53 +01006368 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006369 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006370 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006371 /* we need to always be able to free this, it's safe only in this case */
6372 lyxml_free(mod->ctx, yin);
6373 } else {
6374 /* may try again later, put all back how it was */
6375 stype->der = (struct lys_tpdf *)yin;
6376 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006377 }
Radek Krejcic13db382016-08-16 10:52:42 +02006378 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006379 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006380 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006381 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6382 }
Michal Vaskoc5c55ca2017-06-30 13:15:18 +02006383
6384 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6385 /* fill typedef union leafref flag */
6386 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6387 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6388 /* copy the type in case it has union leafref flag */
6389 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
6390 LOGERR(LY_EINT, "Failed to duplicate type.");
6391 return -1;
6392 }
6393 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006394 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006395 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6396 * by uses statement until the type is resolved. We do that the same way as uses statements inside
Radek Krejci93def382017-05-24 15:33:48 +02006397 * grouping. The grouping cannot be used unless the unres counter is 0.
6398 * To remember that the grouping already increased the counter, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006399 * of the type's base member. */
6400 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6401 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006402 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6403 LOGERR(LY_EINT, "Too many unresolved items (type) inside a grouping.");
6404 return -1;
6405 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006406 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006407 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006408 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006409 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006410 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006411 iff_data = str_snode;
6412 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006413 if (!rc) {
6414 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006415 if (iff_data->infeature) {
6416 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6417 feat = *((struct lys_feature **)item);
6418 if (!feat->depfeatures) {
6419 feat->depfeatures = ly_set_new();
6420 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006421 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006422 }
6423 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006424 lydict_remove(mod->ctx, iff_data->fname);
6425 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006426 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006427 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006428 case UNRES_FEATURE:
6429 feat = (struct lys_feature *)item;
6430
6431 if (feat->iffeature_size) {
6432 refs = ly_set_new();
6433 procs = ly_set_new();
6434 ly_set_add(procs, feat, 0);
6435
6436 while (procs->number) {
6437 ref = procs->set.g[procs->number - 1];
6438 ly_set_rm_index(procs, procs->number - 1);
6439
6440 for (i = 0; i < ref->iffeature_size; i++) {
6441 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6442 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006443 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006444 if (ref->iffeature[i].features[j - 1] == feat) {
6445 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6446 goto featurecheckdone;
6447 }
6448
6449 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6450 k = refs->number;
6451 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6452 /* not yet seen feature, add it for processing */
6453 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6454 }
6455 }
6456 } else {
6457 /* forward reference */
6458 rc = EXIT_FAILURE;
6459 goto featurecheckdone;
6460 }
6461 }
6462
6463 }
6464 }
6465 rc = EXIT_SUCCESS;
6466
6467featurecheckdone:
6468 ly_set_free(refs);
6469 ly_set_free(procs);
6470 }
6471
6472 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006473 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006474 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006475 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006476 case UNRES_TYPEDEF_DFLT:
6477 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006478 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006479 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006480 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006481 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006482 break;
6483 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006484 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006485 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006486 choic = item;
6487
Radek Krejcie00d2312016-08-12 15:27:49 +02006488 if (!choic->dflt) {
6489 choic->dflt = resolve_choice_dflt(choic, expr);
6490 }
Michal Vasko7955b362015-09-04 14:18:15 +02006491 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006492 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006493 } else {
6494 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006495 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006496 break;
6497 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006498 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006499 break;
6500 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006501 unique_info = (struct unres_list_uniq *)item;
6502 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006503 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006504 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006505 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006506 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006507 case UNRES_XPATH:
6508 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006509 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006510 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006511 case UNRES_EXT:
6512 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006513 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006514 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006515 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006516 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006517 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006518 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006519 if (eplugin) {
6520 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006521 u = malloc(sizeof *u);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006522 LY_CHECK_ERR_RETURN(!u, LOGMEM, -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006523 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006524 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6525 /* something really bad happend since the extension finalization is not actually
6526 * being resolved while adding into unres, so something more serious with the unres
6527 * list itself must happened */
6528 return -1;
6529 }
Radek Krejci80056d52017-01-05 13:13:33 +01006530 }
6531 }
Radek Krejci79685c92017-02-17 10:49:43 +01006532 }
6533 if (!rc || rc == -1) {
6534 /* cleanup on success or fatal error */
6535 if (ext_data->datatype == LYS_IN_YIN) {
6536 /* YIN */
6537 lyxml_free(mod->ctx, ext_data->data.yin);
6538 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006539 /* YANG */
6540 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006541 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006542 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006543 }
6544 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006545 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006546 u = (uint8_t *)str_snode;
6547 ext = (*(struct lys_ext_instance ***)item)[*u];
6548 free(u);
6549
Radek Krejci80056d52017-01-05 13:13:33 +01006550 eplugin = ext->def->plugin;
6551
6552 /* inherit */
6553 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6554 root = (struct lys_node *)ext->parent;
6555 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6556 LY_TREE_DFS_BEGIN(root->child, next, node) {
6557 /* first, check if the node already contain instance of the same extension,
6558 * in such a case we won't inherit. In case the node was actually defined as
6559 * augment data, we are supposed to check the same way also the augment node itself */
6560 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6561 goto inherit_dfs_sibling;
6562 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6563 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6564 goto inherit_dfs_sibling;
6565 }
6566
6567 if (eplugin->check_inherit) {
6568 /* we have a callback to check the inheritance, use it */
6569 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6570 case 0:
6571 /* yes - continue with the inheriting code */
6572 break;
6573 case 1:
6574 /* no - continue with the node's sibling */
6575 goto inherit_dfs_sibling;
6576 case 2:
6577 /* no, but continue with the children, just skip the inheriting code for this node */
6578 goto inherit_dfs_child;
6579 default:
6580 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6581 ext->def->module->name, ext->def->name, rc);
6582 }
6583 }
6584
6585 /* inherit the extension */
6586 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006587 LY_CHECK_ERR_RETURN(!extlist, LOGMEM, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006588 extlist[node->ext_size] = malloc(sizeof **extlist);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006589 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM; node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006590 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6591 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6592
6593 node->ext = extlist;
6594 node->ext_size++;
6595
6596inherit_dfs_child:
6597 /* modification of - select element for the next run - children first */
6598 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6599 next = NULL;
6600 } else {
6601 next = node->child;
6602 }
6603 if (!next) {
6604inherit_dfs_sibling:
6605 /* no children, try siblings */
6606 next = node->next;
6607 }
6608 while (!next) {
6609 /* go to the parent */
6610 node = lys_parent(node);
6611
6612 /* we are done if we are back in the root (the starter's parent */
6613 if (node == root) {
6614 break;
6615 }
6616
6617 /* parent is already processed, go to its sibling */
6618 next = node->next;
6619 }
6620 }
6621 }
6622 }
6623
6624 /* final check */
6625 if (eplugin->check_result) {
6626 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006627 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006628 return -1;
6629 }
6630 }
6631
6632 rc = 0;
6633 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006634 default:
6635 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006636 break;
6637 }
6638
Radek Krejci54081ce2016-08-12 15:21:47 +02006639 if (has_str && !rc) {
6640 /* the string is no more needed in case of success.
6641 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006642 lydict_remove(mod->ctx, str_snode);
6643 }
6644
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006645 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006646}
6647
Michal Vaskof02e3742015-08-05 16:27:02 +02006648/* logs directly */
6649static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006650print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006651{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006652 struct lyxml_elem *xml;
6653 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006654 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006655 const char *name = NULL;
6656 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006657
Michal Vaskof02e3742015-08-05 16:27:02 +02006658 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006659 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006660 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006661 break;
6662 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006663 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006664 break;
6665 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006666 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6667 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006668 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006669 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006670 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006671 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006672 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6673 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006674 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006675 } else {
6676 LY_TREE_FOR(xml->attr, attr) {
6677 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006678 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006679 break;
6680 }
6681 }
6682 assert(attr);
6683 }
Radek Krejcie534c132016-11-23 13:32:31 +01006684 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006685 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006686 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006687 iff_data = str_node;
6688 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006689 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006690 case UNRES_FEATURE:
6691 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6692 ((struct lys_feature *)item)->name);
6693 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006694 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006695 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006696 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006697 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006698 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006699 if (str_node) {
6700 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6701 } /* else no default value in the type itself, but we are checking some restrictions against
6702 * possible default value of some base type. The failure is caused by not resolved base type,
6703 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006704 break;
6705 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006706 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006707 break;
6708 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006709 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006710 break;
6711 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006712 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006713 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006714 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006715 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6716 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006717 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006718 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006719 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6720 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006721 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006722 case UNRES_EXT:
6723 extinfo = (struct unres_ext *)str_node;
6724 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6725 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6726 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006727 default:
6728 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006729 break;
6730 }
6731}
6732
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006733/**
Michal Vaskobb211122015-08-19 14:03:11 +02006734 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006735 *
6736 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006737 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006738 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006739 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006740 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006741int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006742resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006743{
Radek Krejci010e54b2016-03-15 09:40:34 +01006744 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006745 struct lyxml_elem *yin;
6746 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006747 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006748
6749 assert(unres);
6750
Michal Vaskoe8734262016-09-29 14:12:06 +02006751 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006752 if (*ly_vlog_hide_location()) {
6753 log_hidden = 1;
6754 } else {
6755 log_hidden = 0;
6756 ly_vlog_hide(1);
6757 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006758
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006759 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006760 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006761 unres_count = 0;
6762 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006763
6764 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006765 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006766 * if-features are resolved here to make sure that we will have all if-features for
6767 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006768 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006769 continue;
6770 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006771 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006772 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006773
Michal Vasko88c29542015-11-27 14:57:53 +01006774 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006775 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006776 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006777 unres->type[i] = UNRES_RESOLVED;
6778 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006779 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006780 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006781 if (!log_hidden) {
6782 ly_vlog_hide(0);
6783 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006784 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006785 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006786 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006787 } else {
6788 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006789 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006790 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006791 }
Michal Vasko88c29542015-11-27 14:57:53 +01006792 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006793
Michal Vasko88c29542015-11-27 14:57:53 +01006794 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006795 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006796 if (!log_hidden) {
6797 ly_vlog_hide(0);
6798 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006799
6800 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006801 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006802 continue;
6803 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006804 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejci63fc0962017-02-15 13:20:18 +01006805 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006806 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6807 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6808 yang =(struct yang_type *)yin;
6809 ((struct lys_type *)unres->item[i])->base = yang->base;
6810 if (yang->base == LY_TYPE_UNION) {
6811 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6812 }
6813 lydict_remove(mod->ctx, yang->name);
6814 free(yang);
6815 } else {
6816 lyxml_free(mod->ctx, yin);
6817 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006818 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006819 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006820 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006821 }
6822
Radek Krejci07d0fb92017-01-13 14:11:05 +01006823 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006824 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006825 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006826 continue;
6827 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006828
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006829 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci010e54b2016-03-15 09:40:34 +01006830 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006831 if (unres->type[i] == UNRES_LIST_UNIQ) {
6832 /* free the allocated structure */
6833 free(unres->item[i]);
6834 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006835 unres->type[i] = UNRES_RESOLVED;
6836 ++resolved;
6837 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006838 if (!log_hidden) {
6839 ly_vlog_hide(0);
6840 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006841 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006842 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006843 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006844 } else {
6845 /* forward reference, erase ly_errno */
6846 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006847 }
6848 }
6849
Michal Vasko74a60c02017-03-08 10:19:48 +01006850 if (!log_hidden) {
6851 ly_vlog_hide(0);
6852 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006853
Radek Krejci80056d52017-01-05 13:13:33 +01006854 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6855 for (i = 0; i < unres->count; ++i) {
6856 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6857 continue;
6858 }
6859
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006860 rc = resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 0);
Radek Krejci791f6c72017-02-22 15:23:39 +01006861 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006862 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006863 ++resolved;
6864 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006865 /* else error - it was already printed, but resolved was not increased,
6866 so this unres item will not be resolved again in the following code,
6867 but it will cause returning -1 at the end, this way we are able to
6868 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006869 }
6870
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006871 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006872 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6873 * all the validation errors
6874 */
6875 for (i = 0; i < unres->count; ++i) {
6876 if (unres->type[i] == UNRES_RESOLVED) {
6877 continue;
6878 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006879 resolve_unres_schema_item(unres->module[i], unres->item[i], unres->type[i], unres->str_snode[i], unres, 1);
Radek Krejcib3142312016-11-09 11:04:12 +01006880 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006881 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006882 unres->type[i] = UNRES_RESOLVED;
6883 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006884 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006885 }
Radek Krejcib3142312016-11-09 11:04:12 +01006886 if (resolved < unres->count) {
6887 return -1;
6888 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006889 }
6890
Michal Vaskoe8734262016-09-29 14:12:06 +02006891 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006892 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006893 return EXIT_SUCCESS;
6894}
6895
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006896/**
Michal Vaskobb211122015-08-19 14:03:11 +02006897 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006898 *
6899 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006900 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006901 * @param[in] item Item to resolve. Type determined by \p type.
6902 * @param[in] type Type of the unresolved item.
6903 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006904 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006905 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006906 */
6907int
Radek Krejci48464ed2016-03-17 15:44:09 +01006908unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6909 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006910{
Radek Krejci54081ce2016-08-12 15:21:47 +02006911 int rc;
6912 const char *dictstr;
6913
6914 dictstr = lydict_insert(mod->ctx, str, 0);
6915 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6916
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006917 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006918 lydict_remove(mod->ctx, dictstr);
6919 }
6920 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006921}
6922
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006923/**
Michal Vaskobb211122015-08-19 14:03:11 +02006924 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006925 *
6926 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006927 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006928 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006929 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006930 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006931 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006932 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6933 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006934 */
6935int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006936unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006937 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006938{
Michal Vaskoef486d72016-09-27 12:10:44 +02006939 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006940 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006941
Michal Vasko9bf425b2015-10-22 11:42:03 +02006942 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6943 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006944
Michal Vasko9e862e82017-03-08 10:20:49 +01006945#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006946 uint32_t u;
6947
Radek Krejci850a5de2016-11-08 14:06:40 +01006948 /* check for duplicities in unres */
6949 for (u = 0; u < unres->count; u++) {
6950 if (unres->type[u] == type && unres->item[u] == item &&
6951 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006952 /* duplication, should not happen */
6953 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006954 }
6955 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006956#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006957
Radek Krejcic293bac2017-02-27 11:25:28 +01006958 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01006959 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01006960 rc = EXIT_FAILURE;
6961 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01006962 if (*ly_vlog_hide_location()) {
6963 log_hidden = 1;
6964 } else {
6965 log_hidden = 0;
6966 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006967 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006968 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006969 if (!log_hidden) {
6970 ly_vlog_hide(0);
6971 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006972
Radek Krejci80056d52017-01-05 13:13:33 +01006973 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02006974 if (rc == -1) {
Radek Krejci80056d52017-01-05 13:13:33 +01006975 ly_err_repeat();
6976 }
6977 if (type == UNRES_LIST_UNIQ) {
6978 /* free the allocated structure */
6979 free(item);
6980 } else if (rc == -1 && type == UNRES_IFFEAT) {
6981 /* free the allocated resources */
6982 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02006983 }
Radek Krejci80056d52017-01-05 13:13:33 +01006984 return rc;
6985 } else {
6986 /* erase info about validation errors */
6987 ly_err_clean(1);
6988 }
Michal Vaskof02e3742015-08-05 16:27:02 +02006989
Radek Krejci80056d52017-01-05 13:13:33 +01006990 print_unres_schema_item_fail(item, type, snode);
6991
6992 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
6993 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
6994 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
6995 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6996 lyxml_unlink_elem(mod->ctx, yin, 1);
6997 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6998 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01006999 }
Michal Vasko88c29542015-11-27 14:57:53 +01007000 }
7001
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007002 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007003 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007004 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007005 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01007006 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007007 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007008 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01007009 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007010 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM, -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007011 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01007012 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007013 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM, -1);
Radek Krejcic071c542016-01-27 14:57:51 +01007014 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007015
Michal Vasko3767fb22016-07-21 12:10:57 +02007016 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007017}
7018
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007019/**
Michal Vaskobb211122015-08-19 14:03:11 +02007020 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007021 *
7022 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007023 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007024 * @param[in] item Old item to be resolved.
7025 * @param[in] type Type of the old unresolved item.
7026 * @param[in] new_item New item to use in the duplicate.
7027 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007028 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007029 */
Michal Vaskodad19402015-08-06 09:51:53 +02007030int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007031unres_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 +02007032{
7033 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007034 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007035 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007036
Michal Vaskocf024702015-10-08 15:01:42 +02007037 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007038
Radek Krejcid09d1a52016-08-11 14:05:45 +02007039 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7040 if (type == UNRES_LIST_UNIQ) {
7041 aux_uniq.list = item;
7042 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7043 item = &aux_uniq;
7044 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007045 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007046
7047 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007048 if (type == UNRES_LIST_UNIQ) {
7049 free(new_item);
7050 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007051 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007052 }
7053
Radek Krejcic79c6b12016-07-26 15:11:49 +02007054 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007055 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007056 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007057 LOGINT;
7058 return -1;
7059 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007060 } else if (type == UNRES_IFFEAT) {
7061 /* duplicate unres_iffeature_data */
7062 iff_data = malloc(sizeof *iff_data);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007063 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM, -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007064 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7065 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7066 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7067 LOGINT;
7068 return -1;
7069 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007070 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007071 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007072 LOGINT;
7073 return -1;
7074 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007075 }
Michal Vaskodad19402015-08-06 09:51:53 +02007076
7077 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007078}
7079
Michal Vaskof02e3742015-08-05 16:27:02 +02007080/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007081int
Michal Vasko878e38d2016-09-05 12:17:53 +02007082unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007083{
Michal Vasko878e38d2016-09-05 12:17:53 +02007084 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007085 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007086
Radek Krejciddddd0d2017-01-20 15:20:46 +01007087 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007088 i = start_on_backwards;
7089 } else {
7090 i = unres->count - 1;
7091 }
7092 for (; i > -1; i--) {
7093 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007094 continue;
7095 }
7096 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007097 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007098 break;
7099 }
7100 } else {
7101 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7102 aux_uniq2 = (struct unres_list_uniq *)item;
7103 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007104 break;
7105 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007106 }
7107 }
7108
Michal Vasko878e38d2016-09-05 12:17:53 +02007109 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007110}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007111
Michal Vaskoede9c472016-06-07 09:38:15 +02007112static void
7113unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7114{
7115 struct lyxml_elem *yin;
7116 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007117 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007118
7119 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007120 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007121 case UNRES_TYPE_DER:
7122 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7123 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7124 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007125 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007126 lydict_remove(ctx, yang->name);
7127 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007128 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7129 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7130 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007131 } else {
7132 lyxml_free(ctx, yin);
7133 }
7134 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007135 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007136 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7137 lydict_remove(ctx, iff_data->fname);
7138 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007139 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007140 case UNRES_IDENT:
7141 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007142 case UNRES_CHOICE_DFLT:
7143 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007144 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7145 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007146 case UNRES_LIST_UNIQ:
7147 free(unres->item[i]);
7148 break;
PavolVicanc1807262017-01-31 18:00:27 +01007149 case UNRES_EXT:
7150 free(unres->str_snode[i]);
7151 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007152 default:
7153 break;
7154 }
7155 unres->type[i] = UNRES_RESOLVED;
7156}
7157
Michal Vasko88c29542015-11-27 14:57:53 +01007158void
Michal Vasko44ab1462017-05-18 13:18:36 +02007159unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007160{
7161 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007162 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007163
Radek Krejcic071c542016-01-27 14:57:51 +01007164 if (!unres || !(*unres)) {
7165 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007166 }
7167
Michal Vasko44ab1462017-05-18 13:18:36 +02007168 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007169
7170 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007171 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007172 if ((*unres)->type[i] != UNRES_RESOLVED) {
7173 unresolved++;
7174 }
7175 continue;
7176 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007177
7178 /* free heap memory for the specific item */
7179 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007180 }
7181
Michal Vaskoede9c472016-06-07 09:38:15 +02007182 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007183 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007184 free((*unres)->item);
7185 free((*unres)->type);
7186 free((*unres)->str_snode);
7187 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007188 free((*unres));
7189 (*unres) = NULL;
7190 }
Michal Vasko88c29542015-11-27 14:57:53 +01007191}
7192
Michal Vaskoff690e72017-08-03 14:25:07 +02007193/* check whether instance-identifier points outside its data subtree (for operation it is any node
7194 * outside the operation subtree, otherwise it is a node from a foreign model) */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007195static int
7196check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7197{
Michal Vaskoff690e72017-08-03 14:25:07 +02007198 const struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007199 char *buf;
Michal Vaskoff690e72017-08-03 14:25:07 +02007200 int ret = 0, hidden;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007201
Radek Krejci034cb102017-08-01 15:45:13 +02007202 if (!json_instid || !json_instid[0]) {
7203 /* no/empty value */
7204 return 0;
7205 }
7206
Michal Vasko3cfa3182017-01-17 10:00:58 +01007207 for (op_node = lys_parent(sleaf);
7208 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7209 op_node = lys_parent(op_node));
7210
7211 if (op_node && lys_parent(op_node)) {
7212 /* nested operation - any absolute path is external */
7213 return 1;
7214 }
7215
7216 /* get the first node from the instid */
7217 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7218 if (!buf) {
7219 LOGMEM;
7220 return -1;
7221 }
7222
Michal Vaskoff690e72017-08-03 14:25:07 +02007223 /* find the first schema node, do not log */
7224 hidden = *ly_vlog_hide_location();
7225 if (!hidden) {
7226 ly_vlog_hide(1);
7227 }
7228 first_node = ly_ctx_get_node(NULL, sleaf, buf, 0);
7229 if (!hidden) {
7230 ly_vlog_hide(0);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007231 }
7232
Michal Vaskoff690e72017-08-03 14:25:07 +02007233 if (!first_node) {
7234 /* unknown path, say it is not external */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007235 free(buf);
Michal Vaskoff690e72017-08-03 14:25:07 +02007236 ly_errno = LYE_SUCCESS;
7237 return 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007238 }
7239 free(buf);
7240
7241 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7242
Michal Vaskoff690e72017-08-03 14:25:07 +02007243 if (op_node && (op_node != first_node)) {
7244 /* it is a top-level operation, so we're good if it points somewhere inside it */
7245 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007246 }
7247
7248 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7249 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007250 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007251}
7252
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007253/**
7254 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7255 *
7256 * @param[in] data Data node where the path is used
7257 * @param[in] path Instance-identifier node value.
7258 * @param[in,out] ret Resolved instance or NULL.
7259 *
7260 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7261 */
7262static int
7263resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7264{
7265 int i = 0, j;
Michal Vasko1b6ca962017-08-03 14:23:09 +02007266 const struct lys_module *mod, *prev_mod = NULL;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007267 struct ly_ctx *ctx = data->schema->module->ctx;
7268 const char *model, *name;
7269 char *str;
7270 int mod_len, name_len, has_predicate;
7271 struct unres_data node_match;
7272
7273 memset(&node_match, 0, sizeof node_match);
7274 *ret = NULL;
7275
7276 /* we need root to resolve absolute path */
7277 for (; data->parent; data = data->parent);
7278 /* we're still parsing it and the pointer is not correct yet */
7279 if (data->prev) {
7280 for (; data->prev->next; data = data->prev);
7281 }
7282
7283 /* search for the instance node */
7284 while (path[i]) {
7285 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7286 if (j <= 0) {
7287 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7288 goto error;
7289 }
7290 i += j;
7291
Michal Vasko1b6ca962017-08-03 14:23:09 +02007292 if (model) {
7293 str = strndup(model, mod_len);
7294 if (!str) {
7295 LOGMEM;
7296 goto error;
Michal Vaskof53187d2017-01-13 13:23:14 +01007297 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007298 mod = ly_ctx_get_module(ctx, str, NULL);
7299 if (ctx->data_clb) {
7300 if (!mod) {
7301 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7302 } else if (!mod->implemented) {
7303 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7304 }
7305 }
7306 free(str);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007307
Michal Vasko1b6ca962017-08-03 14:23:09 +02007308 if (!mod || !mod->implemented || mod->disabled) {
7309 break;
7310 }
7311 } else if (!prev_mod) {
7312 /* first iteration and we are missing module name */
7313 LOGVAL(LYE_INELEM_LEN, LY_VLOG_NONE, NULL, name_len, name);
7314 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Instane-identifier is missing prefix in the first node.");
7315 goto error;
7316 } else {
7317 mod = prev_mod;
Michal Vaskof53187d2017-01-13 13:23:14 +01007318 }
7319
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007320 if (resolve_data(mod, name, name_len, data, &node_match)) {
7321 /* no instance exists */
7322 break;
7323 }
7324
7325 if (has_predicate) {
7326 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1b6ca962017-08-03 14:23:09 +02007327 j = resolve_instid_predicate(mod, &path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007328 if (j < 1) {
7329 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7330 goto error;
7331 }
7332 i += j;
7333
7334 if (!node_match.count) {
7335 /* no instance exists */
7336 break;
7337 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007338 } else if (node_match.count) {
7339 /* check that we are not addressing lists */
7340 for (j = 0; (unsigned)j < node_match.count; ++j) {
7341 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7342 unres_data_del(&node_match, j--);
7343 }
7344 }
7345 if (!node_match.count) {
7346 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7347 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007348 }
Michal Vasko1b6ca962017-08-03 14:23:09 +02007349
7350 prev_mod = mod;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007351 }
7352
7353 if (!node_match.count) {
7354 /* no instance exists */
7355 if (req_inst > -1) {
7356 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7357 return EXIT_FAILURE;
7358 }
7359 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7360 return EXIT_SUCCESS;
7361 } else if (node_match.count > 1) {
7362 /* instance identifier must resolve to a single node */
7363 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7364 goto error;
7365 } else {
7366 /* we have required result, remember it and cleanup */
7367 *ret = node_match.node[0];
7368 free(node_match.node);
7369 return EXIT_SUCCESS;
7370 }
7371
7372error:
7373 /* cleanup */
7374 free(node_match.node);
7375 return -1;
7376}
7377
7378static int
7379resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007380{
Michal Vasko86ae1f22017-07-10 11:50:33 +02007381 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007382 uint32_t i;
7383
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007384 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007385
Michal Vasko86ae1f22017-07-10 11:50:33 +02007386 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007387 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vasko86ae1f22017-07-10 11:50:33 +02007388 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007389 return -1;
7390 }
7391
Michal Vasko86ae1f22017-07-10 11:50:33 +02007392 for (i = 0; i < set->number; ++i) {
7393 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7394 continue;
7395 }
7396
Radek Krejci1899d6a2016-11-03 13:48:07 +01007397 /* not that the value is already in canonical form since the parsers does the conversion,
7398 * so we can simply compare just the values */
Michal Vasko86ae1f22017-07-10 11:50:33 +02007399 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)set->set.d[i])->value_str, 1)) {
Radek Krejci1899d6a2016-11-03 13:48:07 +01007400 /* we have the match */
Michal Vasko86ae1f22017-07-10 11:50:33 +02007401 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007402 break;
7403 }
7404 }
7405
Michal Vasko86ae1f22017-07-10 11:50:33 +02007406 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007407
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007408 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007409 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007410 if (req_inst > -1) {
7411 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007412 return EXIT_FAILURE;
7413 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007414 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 +02007415 }
7416 }
7417
7418 return EXIT_SUCCESS;
7419}
7420
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007421/* 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 +01007422int
7423resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7424 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007425{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007426 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007427 struct lyd_node *ret;
7428 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007429 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007430
7431 assert(type->base == LY_TYPE_UNION);
7432
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007433 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7434 /* either NULL or instid previously converted to JSON */
7435 json_val = leaf->value.string;
7436 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007437
Michal Vaskofd6c6502017-01-06 12:15:41 +01007438 if (store) {
7439 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7440 free(leaf->value.bit);
7441 }
7442 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007443 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007444
7445 /* turn logging off, we are going to try to validate the value with all the types in order */
7446 hidden = *ly_vlog_hide_location();
7447 ly_vlog_hide(1);
7448
7449 t = NULL;
7450 found = 0;
7451 while ((t = lyp_get_next_union_type(type, t, &found))) {
7452 found = 0;
7453
7454 switch (t->base) {
7455 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007456 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7457 req_inst = -1;
7458 } else {
7459 req_inst = t->info.lref.req;
7460 }
7461
7462 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007463 if (store) {
7464 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7465 /* valid resolved */
7466 leaf->value.leafref = ret;
7467 leaf->value_type = LY_TYPE_LEAFREF;
7468 } else {
7469 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007470 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007471 return -1;
7472 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007473 }
7474 }
7475
7476 success = 1;
7477 }
7478 break;
7479 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007480 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
Radek Krejci034cb102017-08-01 15:45:13 +02007481 if (ext_dep == -1) {
7482 return -1;
7483 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01007484 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7485 req_inst = -1;
7486 } else {
7487 req_inst = t->info.inst.req;
7488 }
7489
Michal Vaskod3a03112017-01-23 09:56:02 +01007490 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007491 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007492 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007493 /* valid resolved */
7494 leaf->value.instance = ret;
7495 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007496
Michal Vaskofd6c6502017-01-06 12:15:41 +01007497 if (json_val) {
7498 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7499 leaf->value_str = json_val;
7500 json_val = NULL;
7501 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007502 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007503 /* valid unresolved */
7504 if (json_val) {
7505 /* put the JSON val back */
7506 leaf->value.string = json_val;
7507 json_val = NULL;
7508 } else {
7509 leaf->value.instance = NULL;
7510 }
7511 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007512 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007513 }
7514
7515 success = 1;
7516 }
7517 break;
7518 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007519 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007520 success = 1;
7521 }
7522 break;
7523 }
7524
7525 if (success) {
7526 break;
7527 }
7528
7529 /* erase information about errors - they are false or irrelevant
7530 * and will be replaced by a single error messages */
7531 ly_err_clean(1);
7532
7533 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007534 if (store) {
7535 if (t->base == LY_TYPE_BITS) {
7536 free(leaf->value.bit);
7537 }
7538 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007539 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007540 }
7541
7542 /* turn logging back on */
7543 if (!hidden) {
7544 ly_vlog_hide(0);
7545 }
7546
7547 if (json_val) {
7548 if (!success) {
7549 /* put the value back for now */
7550 assert(leaf->value_type == LY_TYPE_UNION);
7551 leaf->value.string = json_val;
7552 } else {
7553 /* value was ultimately useless, but we could not have known */
7554 lydict_remove(leaf->schema->module->ctx, json_val);
7555 }
7556 }
7557
Michal Vaskofd6c6502017-01-06 12:15:41 +01007558 if (success) {
7559 if (resolved_type) {
7560 *resolved_type = t;
7561 }
7562 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007563 /* not found and it is required */
7564 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007565 return EXIT_FAILURE;
7566 }
7567
7568 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007569
Radek Krejci9b6aad22016-09-20 15:55:51 +02007570}
7571
Michal Vasko8bcdf292015-08-19 14:04:43 +02007572/**
7573 * @brief Resolve a single unres data item. Logs directly.
7574 *
Michal Vaskocf024702015-10-08 15:01:42 +02007575 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007576 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007577 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007578 *
7579 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7580 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007581int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007582resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007583{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007584 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007585 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007586 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007587 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007588
Michal Vasko83a6c462015-10-08 16:43:53 +02007589 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007590 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007591
Michal Vaskocf024702015-10-08 15:01:42 +02007592 switch (type) {
7593 case UNRES_LEAFREF:
7594 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007595 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007596 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7597 req_inst = -1;
7598 } else {
7599 req_inst = sleaf->type.info.lref.req;
7600 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007601 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7602 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007603 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007604 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007605 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7606 free(leaf->value.bit);
7607 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007608 leaf->value.leafref = ret;
7609 leaf->value_type = LY_TYPE_LEAFREF;
7610 } else {
7611 /* valid unresolved */
7612 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007613 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007614 return -1;
7615 }
7616 }
7617 }
7618 leaf->validity &= ~LYD_VAL_LEAFREF;
7619 } else {
7620 return rc;
7621 }
7622 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007623
Michal Vaskocf024702015-10-08 15:01:42 +02007624 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007625 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007626 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7627 if (ext_dep == -1) {
7628 return -1;
7629 }
7630
7631 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7632 req_inst = -1;
7633 } else {
7634 req_inst = sleaf->type.info.inst.req;
7635 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007636 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7637 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007638 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007639 /* valid resolved */
7640 leaf->value.instance = ret;
7641 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007642 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007643 /* valid unresolved */
7644 leaf->value.instance = NULL;
7645 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007646 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007647 } else {
7648 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007649 }
Michal Vaskocf024702015-10-08 15:01:42 +02007650 break;
7651
Radek Krejci7de36cf2016-09-12 16:18:50 +02007652 case UNRES_UNION:
7653 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007654 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007655
Michal Vaskocf024702015-10-08 15:01:42 +02007656 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007657 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007658 return rc;
7659 }
7660 break;
7661
Michal Vaskobf19d252015-10-08 15:39:17 +02007662 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007663 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007664 return rc;
7665 }
7666 break;
7667
7668 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007669 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007670 return rc;
7671 }
7672 break;
7673
Michal Vaskocf024702015-10-08 15:01:42 +02007674 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007675 LOGINT;
7676 return -1;
7677 }
7678
7679 return EXIT_SUCCESS;
7680}
7681
7682/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007683 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007684 *
7685 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007686 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007687 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007688 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007689 */
7690int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007691unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007692{
Radek Krejci03b71f72016-03-16 11:10:09 +01007693 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007694 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007695 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007696
Radek Krejci03b71f72016-03-16 11:10:09 +01007697 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007698 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007699 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007700 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007701 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007702 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007703 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007704
Radek Krejci0b7704f2016-03-18 12:16:14 +01007705 if (type == UNRES_WHEN) {
7706 /* remove previous result */
7707 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007708 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007709
7710 return EXIT_SUCCESS;
7711}
7712
7713/**
7714 * @brief Resolve every unres data item in the structure. Logs directly.
7715 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007716 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7717 * unresolved leafrefs/instids are accepted).
7718 *
7719 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7720 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007721 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007722 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7723 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007724 *
7725 * @return EXIT_SUCCESS on success, -1 on error.
7726 */
7727int
Radek Krejci082c84f2016-10-17 16:33:06 +02007728resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007729{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007730 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007731 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007732 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007733
Radek Krejci082c84f2016-10-17 16:33:06 +02007734 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007735 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007736
7737 if (!unres->count) {
7738 return EXIT_SUCCESS;
7739 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007740
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007741 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 +01007742 ignore_fail = 1;
7743 } else if (options & LYD_OPT_NOEXTDEPS) {
7744 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007745 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007746 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007747 }
7748
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007749 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007750 ly_vlog_hide(1);
7751
Radek Krejci0b7704f2016-03-18 12:16:14 +01007752 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007753 first = 1;
7754 stmt_count = 0;
7755 resolved = 0;
7756 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007757 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007758 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007759 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007760 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007761 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007762 continue;
7763 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007764 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007765 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007766 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007767 }
7768
7769 /* resolve when condition only when all parent when conditions are already resolved */
7770 for (parent = unres->node[i]->parent;
7771 parent && LYD_WHEN_DONE(parent->when_status);
7772 parent = parent->parent) {
7773 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7774 /* the parent node was already unlinked, do not resolve this node,
7775 * it will be removed anyway, so just mark it as resolved
7776 */
7777 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7778 unres->type[i] = UNRES_RESOLVED;
7779 resolved++;
7780 break;
7781 }
7782 }
7783 if (parent) {
7784 continue;
7785 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007786
Michal Vasko3cfa3182017-01-17 10:00:58 +01007787 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007788 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007789 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007790 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007791 /* false when condition */
7792 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007793 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007794 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007795 } /* follows else */
7796
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007797 /* auto-delete */
7798 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7799 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7800
Radek Krejci0c0086a2016-03-24 15:20:28 +01007801 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7802 /* if it has parent non-presence containers that would be empty, we should actually
7803 * remove the container
7804 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007805 for (parent = unres->node[i];
7806 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7807 parent = parent->parent) {
7808 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7809 /* presence container */
7810 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007811 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007812 if (parent->next || parent->prev != parent) {
7813 /* non empty (the child we are in and we are going to remove is not the only child) */
7814 break;
7815 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007816 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007817 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007818
Radek Krejci0c0086a2016-03-24 15:20:28 +01007819 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007820 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007821 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007822
Radek Krejci0b7704f2016-03-18 12:16:14 +01007823 lyd_unlink(unres->node[i]);
7824 unres->type[i] = UNRES_DELETE;
7825 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007826
7827 /* update the rest of unres items */
7828 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007829 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007830 continue;
7831 }
7832
7833 /* test if the node is in subtree to be deleted */
7834 for (parent = unres->node[j]; parent; parent = parent->parent) {
7835 if (parent == unres->node[i]) {
7836 /* yes, it is */
7837 unres->type[j] = UNRES_RESOLVED;
7838 resolved++;
7839 break;
7840 }
7841 }
7842 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007843 } else {
7844 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007845 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007846 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007847 resolved++;
7848 progress = 1;
7849 } else if (rc == -1) {
7850 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007851 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007852 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007853 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007854 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007855 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007856 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007857 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007858
Radek Krejci0b7704f2016-03-18 12:16:14 +01007859 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007860 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007861 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007862 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007863 return -1;
7864 }
7865
7866 for (i = 0; del_items && i < unres->count; i++) {
7867 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7868 if (unres->type[i] != UNRES_DELETE) {
7869 continue;
7870 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007871 if (!unres->node[i]) {
7872 unres->type[i] = UNRES_RESOLVED;
7873 del_items--;
7874 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007875 }
7876
7877 /* really remove the complete subtree */
7878 lyd_free(unres->node[i]);
7879 unres->type[i] = UNRES_RESOLVED;
7880 del_items--;
7881 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007882
7883 /* now leafrefs */
7884 first = 1;
7885 stmt_count = 0;
7886 resolved = 0;
7887 do {
7888 progress = 0;
7889 for (i = 0; i < unres->count; i++) {
7890 if (unres->type[i] != UNRES_LEAFREF) {
7891 continue;
7892 }
7893 if (first) {
7894 /* count leafref nodes in unres list */
7895 stmt_count++;
7896 }
7897
7898 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7899 if (!rc) {
7900 unres->type[i] = UNRES_RESOLVED;
7901 ly_err_clean(1);
7902 resolved++;
7903 progress = 1;
7904 } else if (rc == -1) {
7905 ly_vlog_hide(0);
7906 /* print only this last error */
7907 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7908 return -1;
7909 } /* else forward reference */
7910 }
7911 first = 0;
7912 } while (progress && resolved < stmt_count);
7913
7914 /* do we have some unresolved leafrefs? */
7915 if (stmt_count > resolved) {
7916 ly_vlog_hide(0);
7917 ly_err_repeat();
7918 return -1;
7919 }
7920
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007921 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007922
7923 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007924 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007925 if (unres->type[i] == UNRES_RESOLVED) {
7926 continue;
7927 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007928 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007929
Michal Vasko3cfa3182017-01-17 10:00:58 +01007930 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007931 if (rc) {
7932 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007933 return -1;
7934 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007935
7936 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007937 }
7938
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007939 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007940 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007941 return EXIT_SUCCESS;
7942}