blob: d173765fdc6cd4291babec65cab3bc2da9e2bc0f [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 Vaskob2f40be2016-09-08 16:03:48 +0200648 * (which are mandatory for every node-identifier) 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
Radek Krejci6dc53a22015-08-17 13:27:59 +0200668 if (has_predicate) {
669 *has_predicate = 0;
670 }
671
672 if (id[0] != '/') {
673 return -parsed;
674 }
675
676 ++parsed;
677 ++id;
678
Michal Vaskob2f40be2016-09-08 16:03:48 +0200679 if ((ret = parse_identifier(id)) < 1) {
680 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200681 }
682
Michal Vaskob2f40be2016-09-08 16:03:48 +0200683 *model = id;
684 *mod_len = ret;
685
Radek Krejci6dc53a22015-08-17 13:27:59 +0200686 parsed += ret;
687 id += ret;
688
Michal Vaskob2f40be2016-09-08 16:03:48 +0200689 if (id[0] != ':') {
690 return -parsed;
691 }
692
693 ++parsed;
694 ++id;
695
696 if ((ret = parse_identifier(id)) < 1) {
697 return ret;
698 }
699
700 *name = id;
701 *nam_len = ret;
702
703 parsed += ret;
704 id += ret;
705
Radek Krejci4967cb62016-09-14 16:40:28 +0200706 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200707 *has_predicate = 1;
708 }
709
710 return parsed;
711}
712
713/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200714 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200715 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200716 *
717 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
718 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
719 * ((DQUOTE string DQUOTE) /
720 * (SQUOTE string SQUOTE))
721 * pos = non-negative-integer-value
722 *
Michal Vaskobb211122015-08-19 14:03:11 +0200723 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200724 * @param[out] model Points to the model name.
725 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200726 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
727 * @param[out] nam_len Length of the node name.
728 * @param[out] value Value the node-identifier must have (string from the grammar),
729 * NULL if there is not any.
730 * @param[out] val_len Length of the value, 0 if there is not any.
731 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
732 *
733 * @return Number of characters successfully parsed,
734 * positive on success, negative on failure.
735 */
736static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200737parse_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
738 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200739{
740 const char *ptr;
741 int parsed = 0, ret;
742 char quote;
743
744 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200745 if (model) {
746 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200747 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200748 if (mod_len) {
749 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200750 }
751 if (name) {
752 *name = NULL;
753 }
754 if (nam_len) {
755 *nam_len = 0;
756 }
757 if (value) {
758 *value = NULL;
759 }
760 if (val_len) {
761 *val_len = 0;
762 }
763 if (has_predicate) {
764 *has_predicate = 0;
765 }
766
767 if (id[0] != '[') {
768 return -parsed;
769 }
770
771 ++parsed;
772 ++id;
773
774 while (isspace(id[0])) {
775 ++parsed;
776 ++id;
777 }
778
779 /* pos */
780 if (isdigit(id[0])) {
781 if (name) {
782 *name = id;
783 }
784
785 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200786 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200787 }
788
789 while (isdigit(id[0])) {
790 ++parsed;
791 ++id;
792 }
793
794 if (nam_len) {
795 *nam_len = id-(*name);
796 }
797
Michal Vaskof2f28a12016-09-09 12:43:06 +0200798 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200799 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200800 if (id[0] == '.') {
801 if (name) {
802 *name = id;
803 }
804 if (nam_len) {
805 *nam_len = 1;
806 }
807
808 ++parsed;
809 ++id;
810
811 } else {
Michal Vasko50576712017-07-28 12:28:33 +0200812 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len, NULL, 0)) < 1) {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200813 return -parsed+ret;
814 } else if (model && !*model) {
815 return -parsed;
816 }
817
818 parsed += ret;
819 id += ret;
820 }
821
822 while (isspace(id[0])) {
823 ++parsed;
824 ++id;
825 }
826
827 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200828 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200829 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200830
Radek Krejci6dc53a22015-08-17 13:27:59 +0200831 ++parsed;
832 ++id;
833
Michal Vaskof2f28a12016-09-09 12:43:06 +0200834 while (isspace(id[0])) {
835 ++parsed;
836 ++id;
837 }
838
839 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
840 if ((id[0] == '\"') || (id[0] == '\'')) {
841 quote = id[0];
842
843 ++parsed;
844 ++id;
845
846 if ((ptr = strchr(id, quote)) == NULL) {
847 return -parsed;
848 }
849 ret = ptr-id;
850
851 if (value) {
852 *value = id;
853 }
854 if (val_len) {
855 *val_len = ret;
856 }
857
858 parsed += ret+1;
859 id += ret+1;
860 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200861 return -parsed;
862 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200863 }
864
865 while (isspace(id[0])) {
866 ++parsed;
867 ++id;
868 }
869
870 if (id[0] != ']') {
871 return -parsed;
872 }
873
874 ++parsed;
875 ++id;
876
877 if ((id[0] == '[') && has_predicate) {
878 *has_predicate = 1;
879 }
880
881 return parsed;
882}
883
884/**
885 * @brief Parse schema-nodeid.
886 *
887 * schema-nodeid = absolute-schema-nodeid /
888 * descendant-schema-nodeid
889 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200890 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200891 * node-identifier
892 * absolute-schema-nodeid
893 *
Michal Vaskobb211122015-08-19 14:03:11 +0200894 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200895 * @param[out] mod_name Points to the module name, NULL if there is not any.
896 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200897 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200898 * @param[out] nam_len Length of the node name.
899 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
900 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100901 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
902 * based on the grammar, in those cases use NULL.
Michal Vasko50576712017-07-28 12:28:33 +0200903 * @param[in] extended Whether to accept an extended path (support for /[prefix:]*, //[prefix:]*, //[prefix:].).
Radek Krejci6dc53a22015-08-17 13:27:59 +0200904 *
905 * @return Number of characters successfully parsed,
906 * positive on success, negative on failure.
907 */
Michal Vasko22448d32016-03-16 13:17:29 +0100908int
Michal Vasko723e50c2015-10-20 15:20:29 +0200909parse_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 +0200910 int *is_relative, int *has_predicate, int *all_desc, int extended)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200911{
912 int parsed = 0, ret;
913
914 assert(id);
915 assert(is_relative);
Michal Vasko50576712017-07-28 12:28:33 +0200916
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100917 if (has_predicate) {
918 *has_predicate = 0;
919 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200920
921 if (id[0] != '/') {
922 if (*is_relative != -1) {
923 return -parsed;
924 } else {
925 *is_relative = 1;
926 }
Michal Vasko48935352016-03-29 11:52:36 +0200927 if (!strncmp(id, "./", 2)) {
928 parsed += 2;
929 id += 2;
930 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200931 } else {
932 if (*is_relative == -1) {
933 *is_relative = 0;
934 }
935 ++parsed;
936 ++id;
937 }
938
Michal Vasko50576712017-07-28 12:28:33 +0200939 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len, all_desc, extended)) < 1) {
940 return -parsed + ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200941 }
942
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100943 parsed += ret;
944 id += ret;
945
946 if ((id[0] == '[') && has_predicate) {
947 *has_predicate = 1;
948 }
949
950 return parsed;
951}
952
953/**
954 * @brief Parse schema predicate (special format internally used).
955 *
956 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vaskof359b022017-07-04 13:50:04 +0200957 * predicate-expr = "." / [prefix:]identifier / positive-integer / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100958 * key-with-value = identifier *WSP "=" *WSP
959 * ((DQUOTE string DQUOTE) /
960 * (SQUOTE string SQUOTE))
961 *
962 * @param[in] id Identifier to use.
Michal Vaskof359b022017-07-04 13:50:04 +0200963 * @param[out] mod_name Points to the list key module name.
964 * @param[out] mod_name_len Length of \p mod_name.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100965 * @param[out] name Points to the list key name.
966 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100967 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100968 * @param[out] val_len Length of \p value.
969 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
970 */
Michal Vasko22448d32016-03-16 13:17:29 +0100971int
Michal Vaskof359b022017-07-04 13:50:04 +0200972parse_schema_json_predicate(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
973 const char **value, int *val_len, int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100974{
975 const char *ptr;
976 int parsed = 0, ret;
977 char quote;
978
979 assert(id);
Michal Vaskof359b022017-07-04 13:50:04 +0200980 if (mod_name) {
981 *mod_name = NULL;
982 }
983 if (mod_name_len) {
984 *mod_name_len = 0;
985 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100986 if (name) {
987 *name = NULL;
988 }
989 if (nam_len) {
990 *nam_len = 0;
991 }
992 if (value) {
993 *value = NULL;
994 }
995 if (val_len) {
996 *val_len = 0;
997 }
998 if (has_predicate) {
999 *has_predicate = 0;
1000 }
1001
1002 if (id[0] != '[') {
1003 return -parsed;
1004 }
1005
1006 ++parsed;
1007 ++id;
1008
1009 while (isspace(id[0])) {
1010 ++parsed;
1011 ++id;
1012 }
1013
Michal Vasko22448d32016-03-16 13:17:29 +01001014 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001015 if (id[0] == '.') {
1016 ret = 1;
Michal Vaskof359b022017-07-04 13:50:04 +02001017
1018 if (name) {
1019 *name = id;
1020 }
1021 if (nam_len) {
1022 *nam_len = ret;
1023 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01001024 } else if (isdigit(id[0])) {
1025 if (id[0] == '0') {
1026 return -parsed;
1027 }
1028 ret = 1;
1029 while (isdigit(id[ret])) {
1030 ++ret;
1031 }
Michal Vaskof359b022017-07-04 13:50:04 +02001032
1033 if (name) {
1034 *name = id;
1035 }
1036 if (nam_len) {
1037 *nam_len = ret;
1038 }
Michal Vasko50576712017-07-28 12:28:33 +02001039 } 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 +01001040 return -parsed + ret;
1041 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001042
1043 parsed += ret;
1044 id += ret;
1045
1046 while (isspace(id[0])) {
1047 ++parsed;
1048 ++id;
1049 }
1050
1051 /* there is value as well */
1052 if (id[0] == '=') {
Michal Vasko58c2aab2017-01-05 10:02:05 +01001053 if (name && isdigit(**name)) {
1054 return -parsed;
1055 }
1056
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001057 ++parsed;
1058 ++id;
1059
1060 while (isspace(id[0])) {
1061 ++parsed;
1062 ++id;
1063 }
1064
1065 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
1066 if ((id[0] == '\"') || (id[0] == '\'')) {
1067 quote = id[0];
1068
1069 ++parsed;
1070 ++id;
1071
1072 if ((ptr = strchr(id, quote)) == NULL) {
1073 return -parsed;
1074 }
1075 ret = ptr - id;
1076
1077 if (value) {
1078 *value = id;
1079 }
1080 if (val_len) {
1081 *val_len = ret;
1082 }
1083
1084 parsed += ret + 1;
1085 id += ret + 1;
1086 } else {
1087 return -parsed;
1088 }
1089
1090 while (isspace(id[0])) {
1091 ++parsed;
1092 ++id;
1093 }
1094 }
1095
1096 if (id[0] != ']') {
1097 return -parsed;
1098 }
1099
1100 ++parsed;
1101 ++id;
1102
1103 if ((id[0] == '[') && has_predicate) {
1104 *has_predicate = 1;
1105 }
1106
1107 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001108}
1109
1110/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001111 * @brief Resolve (find) a feature definition. Logs directly.
1112 *
1113 * @param[in] feat_name Feature name to resolve.
1114 * @param[in] len Length of \p feat_name.
1115 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001116 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1117 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001118 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001119 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001120 */
1121static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001122resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001123{
1124 char *str;
1125 const char *mod_name, *name;
1126 int mod_name_len, nam_len, i, j;
1127 const struct lys_module *module;
1128
Radek Krejci9ff0a922016-07-14 13:08:05 +02001129 assert(feature);
1130
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001131 /* check prefix */
Michal Vasko50576712017-07-28 12:28:33 +02001132 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 +02001133 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1134 return -1;
1135 }
1136
1137 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1138 if (!module) {
1139 /* identity refers unknown data model */
1140 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1141 return -1;
1142 }
1143
Radek Krejci9ff0a922016-07-14 13:08:05 +02001144 if (module != node->module && module == lys_node_module(node)) {
1145 /* first, try to search directly in submodule where the feature was mentioned */
1146 for (j = 0; j < node->module->features_size; j++) {
1147 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1148 /* check status */
1149 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001150 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001151 return -1;
1152 }
1153 *feature = &node->module->features[j];
1154 return 0;
1155 }
1156 }
1157 }
1158
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001159 /* search in the identified module ... */
1160 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001161 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001162 /* check status */
1163 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001164 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001165 return -1;
1166 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001167 *feature = &module->features[j];
1168 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001169 }
1170 }
1171 /* ... and all its submodules */
Radek Krejcid4c1d0f2017-01-19 16:11:38 +01001172 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001173 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001174 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1175 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001176 /* check status */
1177 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1178 module->inc[i].submodule->features[j].flags,
1179 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001180 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001181 return -1;
1182 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001183 *feature = &module->inc[i].submodule->features[j];
1184 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001185 }
1186 }
1187 }
1188
1189 /* not found */
1190 str = strndup(feat_name, len);
1191 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1192 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001193 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001194}
1195
Radek Krejci9ff0a922016-07-14 13:08:05 +02001196/*
1197 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001198 * - 1 if enabled
1199 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001200 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001201static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001202resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001203{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001204 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001205
Radek Krejci9ff0a922016-07-14 13:08:05 +02001206 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001207 if (!resolve_iffeature(&feat->iffeature[i])) {
Radek Krejciaf566332017-02-07 15:56:59 +01001208 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001209 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001210 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001211
Radek Krejci69b8d922016-07-27 13:13:41 +02001212 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001213}
1214
1215static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001216resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001217{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001218 uint8_t op;
Radek Krejciaf566332017-02-07 15:56:59 +01001219 int a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001220
Radek Krejci9ff0a922016-07-14 13:08:05 +02001221 op = iff_getop(expr->expr, *index_e);
1222 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001223
Radek Krejci9ff0a922016-07-14 13:08:05 +02001224 switch (op) {
1225 case LYS_IFF_F:
1226 /* resolve feature */
1227 return resolve_feature_value(expr->features[(*index_f)++]);
1228 case LYS_IFF_NOT:
Radek Krejciaf566332017-02-07 15:56:59 +01001229 /* invert result */
1230 return resolve_iffeature_recursive(expr, index_e, index_f) ? 0 : 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001231 case LYS_IFF_AND:
1232 case LYS_IFF_OR:
1233 a = resolve_iffeature_recursive(expr, index_e, index_f);
1234 b = resolve_iffeature_recursive(expr, index_e, index_f);
Radek Krejciaf566332017-02-07 15:56:59 +01001235 if (op == LYS_IFF_AND) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001236 return a && b;
1237 } else { /* LYS_IFF_OR */
1238 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001239 }
1240 }
1241
Radek Krejciaf566332017-02-07 15:56:59 +01001242 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001243}
1244
1245int
1246resolve_iffeature(struct lys_iffeature *expr)
1247{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001248 int index_e = 0, index_f = 0;
1249
1250 if (expr->expr) {
Radek Krejciaf566332017-02-07 15:56:59 +01001251 return resolve_iffeature_recursive(expr, &index_e, &index_f);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001252 }
Radek Krejciaf566332017-02-07 15:56:59 +01001253 return 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001254}
1255
1256struct iff_stack {
1257 int size;
1258 int index; /* first empty item */
1259 uint8_t *stack;
1260};
1261
1262static int
1263iff_stack_push(struct iff_stack *stack, uint8_t value)
1264{
1265 if (stack->index == stack->size) {
1266 stack->size += 4;
1267 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001268 LY_CHECK_ERR_RETURN(!stack->stack, LOGMEM; stack->size = 0, EXIT_FAILURE);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001269 }
1270
1271 stack->stack[stack->index++] = value;
1272 return EXIT_SUCCESS;
1273}
1274
1275static uint8_t
1276iff_stack_pop(struct iff_stack *stack)
1277{
1278 stack->index--;
1279 return stack->stack[stack->index];
1280}
1281
1282static void
1283iff_stack_clean(struct iff_stack *stack)
1284{
1285 stack->size = 0;
1286 free(stack->stack);
1287}
1288
1289static void
1290iff_setop(uint8_t *list, uint8_t op, int pos)
1291{
1292 uint8_t *item;
1293 uint8_t mask = 3;
1294
1295 assert(pos >= 0);
1296 assert(op <= 3); /* max 2 bits */
1297
1298 item = &list[pos / 4];
1299 mask = mask << 2 * (pos % 4);
1300 *item = (*item) & ~mask;
1301 *item = (*item) | (op << 2 * (pos % 4));
1302}
1303
1304uint8_t
1305iff_getop(uint8_t *list, int pos)
1306{
1307 uint8_t *item;
1308 uint8_t mask = 3, result;
1309
1310 assert(pos >= 0);
1311
1312 item = &list[pos / 4];
1313 result = (*item) & (mask << 2 * (pos % 4));
1314 return result >> 2 * (pos % 4);
1315}
1316
1317#define LYS_IFF_LP 0x04 /* ( */
1318#define LYS_IFF_RP 0x08 /* ) */
1319
Radek Krejcicbb473e2016-09-16 14:48:32 +02001320/* internal structure for passing data for UNRES_IFFEAT */
1321struct unres_iffeat_data {
1322 struct lys_node *node;
1323 const char *fname;
Radek Krejci9de2c042016-10-19 16:53:06 +02001324 int infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001325};
1326
Radek Krejci9ff0a922016-07-14 13:08:05 +02001327void
1328resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1329{
1330 unsigned int e = 0, f = 0, r = 0;
1331 uint8_t op;
1332
1333 assert(iffeat);
1334
1335 if (!iffeat->expr) {
1336 goto result;
1337 }
1338
1339 do {
1340 op = iff_getop(iffeat->expr, e++);
1341 switch (op) {
1342 case LYS_IFF_NOT:
1343 if (!r) {
1344 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001345 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001346 break;
1347 case LYS_IFF_AND:
1348 case LYS_IFF_OR:
1349 if (!r) {
1350 r += 2;
1351 } else {
1352 r += 1;
1353 }
1354 break;
1355 case LYS_IFF_F:
1356 f++;
1357 if (r) {
1358 r--;
1359 }
1360 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001361 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001362 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001363
Radek Krejci9ff0a922016-07-14 13:08:05 +02001364result:
1365 if (expr_size) {
1366 *expr_size = e;
1367 }
1368 if (feat_size) {
1369 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001370 }
1371}
1372
1373int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001374resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
Radek Krejci9de2c042016-10-19 16:53:06 +02001375 int infeature, struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001376{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001377 const char *c = value;
1378 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001379 int i, j, last_not, checkversion = 0;
1380 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001381 uint8_t op;
1382 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001383 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001384
Radek Krejci9ff0a922016-07-14 13:08:05 +02001385 assert(c);
1386
1387 if (isspace(c[0])) {
1388 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1389 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001390 }
1391
Radek Krejci9ff0a922016-07-14 13:08:05 +02001392 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1393 for (i = j = last_not = 0; c[i]; i++) {
1394 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001395 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001396 j++;
1397 continue;
1398 } else if (c[i] == ')') {
1399 j--;
1400 continue;
1401 } else if (isspace(c[i])) {
1402 continue;
1403 }
1404
1405 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1406 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001407 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001408 return EXIT_FAILURE;
1409 } else if (!isspace(c[i + r])) {
1410 /* feature name starting with the not/and/or */
1411 last_not = 0;
1412 f_size++;
1413 } else if (c[i] == 'n') { /* not operation */
1414 if (last_not) {
1415 /* double not */
1416 expr_size = expr_size - 2;
1417 last_not = 0;
1418 } else {
1419 last_not = 1;
1420 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001421 } else { /* and, or */
1422 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001423 /* not a not operation */
1424 last_not = 0;
1425 }
1426 i += r;
1427 } else {
1428 f_size++;
1429 last_not = 0;
1430 }
1431 expr_size++;
1432
1433 while (!isspace(c[i])) {
1434 if (!c[i] || c[i] == ')') {
1435 i--;
1436 break;
1437 }
1438 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001439 }
1440 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001441 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001442 /* not matching count of ( and ) */
1443 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1444 return EXIT_FAILURE;
1445 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001446
Radek Krejci69b8d922016-07-27 13:13:41 +02001447 if (checkversion || expr_size > 1) {
1448 /* check that we have 1.1 module */
1449 if (node->module->version != 2) {
1450 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1451 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1452 return EXIT_FAILURE;
1453 }
1454 }
1455
Radek Krejci9ff0a922016-07-14 13:08:05 +02001456 /* allocate the memory */
1457 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001458 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001459 stack.stack = malloc(expr_size * sizeof *stack.stack);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001460 LY_CHECK_ERR_GOTO(!stack.stack || !iffeat_expr->expr || !iffeat_expr->features, LOGMEM, error);
1461 stack.size = expr_size;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001462 f_size--; expr_size--; /* used as indexes from now */
1463
1464 for (i--; i >= 0; i--) {
1465 if (c[i] == ')') {
1466 /* push it on stack */
1467 iff_stack_push(&stack, LYS_IFF_RP);
1468 continue;
1469 } else if (c[i] == '(') {
1470 /* pop from the stack into result all operators until ) */
1471 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1472 iff_setop(iffeat_expr->expr, op, expr_size--);
1473 }
1474 continue;
1475 } else if (isspace(c[i])) {
1476 continue;
1477 }
1478
1479 /* end operator or operand -> find beginning and get what is it */
1480 j = i + 1;
1481 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1482 i--;
1483 }
1484 i++; /* get back by one step */
1485
1486 if (!strncmp(&c[i], "not ", 4)) {
1487 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1488 /* double not */
1489 iff_stack_pop(&stack);
1490 } else {
1491 /* not has the highest priority, so do not pop from the stack
1492 * as in case of AND and OR */
1493 iff_stack_push(&stack, LYS_IFF_NOT);
1494 }
1495 } else if (!strncmp(&c[i], "and ", 4)) {
1496 /* as for OR - pop from the stack all operators with the same or higher
1497 * priority and store them to the result, then push the AND to the stack */
1498 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1499 op = iff_stack_pop(&stack);
1500 iff_setop(iffeat_expr->expr, op, expr_size--);
1501 }
1502 iff_stack_push(&stack, LYS_IFF_AND);
1503 } else if (!strncmp(&c[i], "or ", 3)) {
1504 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1505 op = iff_stack_pop(&stack);
1506 iff_setop(iffeat_expr->expr, op, expr_size--);
1507 }
1508 iff_stack_push(&stack, LYS_IFF_OR);
1509 } else {
1510 /* feature name, length is j - i */
1511
1512 /* add it to the result */
1513 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1514
1515 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001516 * forward referenced, we have to keep the feature name in auxiliary
1517 * structure passed into unres */
1518 iff_data = malloc(sizeof *iff_data);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001519 LY_CHECK_ERR_GOTO(!iff_data, LOGMEM, error);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001520 iff_data->node = node;
1521 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
Radek Krejci9de2c042016-10-19 16:53:06 +02001522 iff_data->infeature = infeature;
Radek Krejcicbb473e2016-09-16 14:48:32 +02001523 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1524 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001525 f_size--;
1526
1527 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001528 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001529 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001530 }
1531 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001532 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001533 while (stack.index) {
1534 op = iff_stack_pop(&stack);
1535 iff_setop(iffeat_expr->expr, op, expr_size--);
1536 }
1537
1538 if (++expr_size || ++f_size) {
1539 /* not all expected operators and operands found */
1540 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1541 rc = EXIT_FAILURE;
1542 } else {
1543 rc = EXIT_SUCCESS;
1544 }
1545
1546error:
1547 /* cleanup */
1548 iff_stack_clean(&stack);
1549
1550 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001551}
1552
1553/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001554 * @brief Resolve (find) a data node based on a schema-nodeid.
1555 *
1556 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1557 * module).
1558 *
1559 */
1560struct lyd_node *
1561resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1562{
1563 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001564 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001565 const struct lys_node *schema = NULL;
1566
1567 assert(nodeid && start);
1568
1569 if (nodeid[0] == '/') {
1570 return NULL;
1571 }
1572
1573 str = p = strdup(nodeid);
Radek Krejcia8d111f2017-05-31 13:57:37 +02001574 LY_CHECK_ERR_RETURN(!str, LOGMEM, NULL);
Radek Krejci5da4eb62016-04-08 14:45:51 +02001575
Michal Vasko3edeaf72016-02-11 13:17:43 +01001576 while (p) {
1577 token = p;
1578 p = strchr(p, '/');
1579 if (p) {
1580 *p = '\0';
1581 p++;
1582 }
1583
Radek Krejci5da4eb62016-04-08 14:45:51 +02001584 if (p) {
1585 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001586 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Michal Vaskodc300b02017-04-07 14:09:20 +02001587 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001588 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001589 result = NULL;
1590 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001591 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001592
Radek Krejci5da4eb62016-04-08 14:45:51 +02001593 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1594 continue;
1595 }
1596 } else {
1597 /* final node */
Michal Vaskodc300b02017-04-07 14:09:20 +02001598 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001599 || !schema) {
1600 result = NULL;
1601 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001602 }
1603 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001604 LY_TREE_FOR(result ? result->child : start, iter) {
1605 if (iter->schema == schema) {
1606 /* move in data tree according to returned schema */
1607 result = iter;
1608 break;
1609 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001610 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001611 if (!iter) {
1612 /* instance not found */
1613 result = NULL;
1614 break;
1615 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001616 }
1617 free(str);
1618
1619 return result;
1620}
1621
Radek Krejci1a9c3612017-04-24 14:49:43 +02001622int
Michal Vasko50576712017-07-28 12:28:33 +02001623schema_nodeid_siblingcheck(const struct lys_node *sibling, const struct lys_module *cur_module, const char *mod_name,
1624 int mod_name_len, const char *name, int nam_len)
Radek Krejcibdf92362016-04-08 14:43:34 +02001625{
1626 const struct lys_module *prefix_mod;
1627
Michal Vasko50576712017-07-28 12:28:33 +02001628 /* name check */
1629 if ((name[0] != '*') && (name[0] != '.') && (strncmp(name, sibling->name, nam_len) || sibling->name[nam_len])) {
1630 return 1;
1631 }
1632
Radek Krejcibdf92362016-04-08 14:43:34 +02001633 /* module check */
Michal Vasko50576712017-07-28 12:28:33 +02001634 if (mod_name) {
1635 prefix_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
1636 if (!prefix_mod) {
1637 return -1;
1638 }
1639 } else {
1640 prefix_mod = cur_module;
Radek Krejcibdf92362016-04-08 14:43:34 +02001641 }
1642 if (prefix_mod != lys_node_module(sibling)) {
1643 return 1;
1644 }
1645
Michal Vasko50576712017-07-28 12:28:33 +02001646 /* match */
1647 switch (name[0]) {
1648 case '*':
1649 return 2;
1650 case '.':
1651 return 3;
1652 default:
Radek Krejcibdf92362016-04-08 14:43:34 +02001653 return 0;
1654 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001655}
1656
Michal Vasko50576712017-07-28 12:28:33 +02001657/* keys do not have to be ordered and do not have to be all of them */
1658static int
1659resolve_extended_schema_nodeid_predicate(const char *nodeid, const struct lys_node *node,
1660 const struct lys_module *cur_module, int *nodeid_end)
1661{
1662 int mod_len, nam_len, has_predicate, r, i;
1663 const char *model, *name;
1664 struct lys_node_list *list;
1665
1666 if (!(node->nodetype & (LYS_LIST | LYS_LEAFLIST))) {
1667 return 1;
1668 }
1669
1670 list = (struct lys_node_list *)node;
1671 do {
1672 r = parse_schema_json_predicate(nodeid, &model, &mod_len, &name, &nam_len, NULL, NULL, &has_predicate);
1673 if (r < 1) {
1674 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, nodeid[r], &nodeid[r]);
1675 return -1;
1676 }
1677 nodeid += r;
1678
1679 if (node->nodetype == LYS_LEAFLIST) {
1680 /* just check syntax */
1681 if (model || !name || (name[0] != '.') || has_predicate) {
1682 return 1;
1683 }
1684 break;
1685 } else {
1686 /* check the key */
1687 for (i = 0; i < list->keys_size; ++i) {
1688 if (strncmp(list->keys[i]->name, name, nam_len) || list->keys[i]->name[nam_len]) {
1689 continue;
1690 }
1691 if (model) {
1692 if (strncmp(lys_node_module((struct lys_node *)list->keys[i])->name, model, mod_len)
1693 || lys_node_module((struct lys_node *)list->keys[i])->name[mod_len]) {
1694 continue;
1695 }
1696 } else {
1697 if (lys_node_module((struct lys_node *)list->keys[i]) != cur_module) {
1698 continue;
1699 }
1700 }
1701
1702 /* match */
1703 break;
1704 }
1705
1706 if (i == list->keys_size) {
1707 return 1;
1708 }
1709 }
1710 } while (has_predicate);
1711
1712 if (!nodeid[0]) {
1713 *nodeid_end = 1;
1714 }
1715 return 0;
1716}
1717
1718/* start - relative, module - absolute, -1 error (logged), EXIT_SUCCESS ok
Radek Krejcidf46e222016-11-08 11:57:37 +01001719 */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001720int
Michal Vasko50576712017-07-28 12:28:33 +02001721resolve_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *cur_module,
1722 struct ly_set **ret, int extended, int no_node_error)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001723{
Michal Vaskobb520442017-05-23 10:55:18 +02001724 const char *name, *mod_name, *id;
Michal Vasko50576712017-07-28 12:28:33 +02001725 const struct lys_node *sibling, *start_parent, *next, *elem;
Michal Vaskobb520442017-05-23 10:55:18 +02001726 struct lys_node_augment *last_aug;
Michal Vasko50576712017-07-28 12:28:33 +02001727 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 +01001728 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcidf46e222016-11-08 11:57:37 +01001729 const struct lys_module *start_mod, *aux_mod;
Michal Vasko50576712017-07-28 12:28:33 +02001730 char *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001731
Michal Vasko50576712017-07-28 12:28:33 +02001732 assert(nodeid && (start || cur_module) && ret);
1733 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001734
Michal Vasko50576712017-07-28 12:28:33 +02001735 if (!cur_module) {
1736 cur_module = lys_node_module(start);
1737 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001738 id = nodeid;
1739
Michal Vasko50576712017-07-28 12:28:33 +02001740 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1741 (extended ? &all_desc : NULL), extended);
1742 if (r < 1) {
1743 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1744 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001745 }
1746 id += r;
1747
Michal Vasko50576712017-07-28 12:28:33 +02001748 if (is_relative && !start) {
1749 LOGINT;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001750 return -1;
1751 }
1752
1753 /* descendant-schema-nodeid */
1754 if (is_relative) {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001755 cur_module = start_mod = start->module;
Michal Vasko24476fa2017-03-08 12:33:48 +01001756 start_parent = lys_parent(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01001757
Michal Vasko3edeaf72016-02-11 13:17:43 +01001758 /* absolute-schema-nodeid */
1759 } else {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001760 start_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001761 if (!start_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001762 str = strndup(mod_name, mod_name_len);
1763 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1764 free(str);
Michal Vaskoe2905632016-02-11 15:42:24 +01001765 return -1;
1766 }
Michal Vasko24476fa2017-03-08 12:33:48 +01001767 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001768 }
1769
1770 while (1) {
1771 sibling = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02001772 last_aug = NULL;
1773
1774 if (start_parent) {
Michal Vasko17315772017-07-10 15:15:39 +02001775 if (mod_name && (strncmp(mod_name, cur_module->name, mod_name_len)
1776 || (mod_name_len != (signed)strlen(cur_module->name)))) {
Michal Vaskobb520442017-05-23 10:55:18 +02001777 /* we are getting into another module (augment) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02001778 aux_mod = lys_get_import_module(cur_module, NULL, 0, mod_name, mod_name_len);
Michal Vaskobb520442017-05-23 10:55:18 +02001779 if (!aux_mod) {
Michal Vasko50576712017-07-28 12:28:33 +02001780 str = strndup(mod_name, mod_name_len);
1781 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1782 free(str);
Michal Vaskobb520442017-05-23 10:55:18 +02001783 return -1;
1784 }
1785 } else {
Michal Vasko17315772017-07-10 15:15:39 +02001786 /* there is no mod_name, so why are we checking augments again?
Michal Vaskobb520442017-05-23 10:55:18 +02001787 * because this module may be not implemented and it augments something in another module and
1788 * there is another augment augmenting that previous one */
Michal Vasko17315772017-07-10 15:15:39 +02001789 aux_mod = cur_module;
Michal Vaskobb520442017-05-23 10:55:18 +02001790 }
1791
1792 /* if the module is implemented, all the augments will be connected */
Michal Vasko50576712017-07-28 12:28:33 +02001793 if (!aux_mod->implemented && !extended) {
Michal Vaskobb520442017-05-23 10:55:18 +02001794get_next_augment:
1795 last_aug = lys_getnext_target_aug(last_aug, aux_mod, start_parent);
1796 }
1797 }
1798
1799 while ((sibling = lys_getnext(sibling, (last_aug ? (struct lys_node *)last_aug : start_parent), start_mod,
Michal Vasko5b997902017-04-03 14:16:22 +02001800 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001801 r = schema_nodeid_siblingcheck(sibling, cur_module, mod_name, mod_name_len, name, nam_len);
1802
1803 /* resolve predicate */
1804 if (extended && ((r == 0) || (r == 2) || (r == 3)) && has_predicate) {
1805 r = resolve_extended_schema_nodeid_predicate(id, sibling, cur_module, &nodeid_end);
1806 if (r == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001807 continue;
Michal Vasko50576712017-07-28 12:28:33 +02001808 } else if (r == -1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001809 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001810 }
Michal Vasko50576712017-07-28 12:28:33 +02001811 } else if (!id[0]) {
1812 nodeid_end = 1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001813 }
Michal Vasko50576712017-07-28 12:28:33 +02001814
1815 if (r == 0) {
1816 /* one matching result */
1817 if (nodeid_end) {
1818 *ret = ly_set_new();
1819 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1820 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1821 } else {
1822 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
1823 return -1;
1824 }
1825 start_parent = sibling;
1826 }
1827 break;
1828 } else if (r == 1) {
1829 continue;
1830 } else if (r == 2) {
1831 /* "*" */
1832 if (!*ret) {
1833 *ret = ly_set_new();
1834 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1835 }
1836 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1837 if (all_desc) {
1838 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1839 if (elem != sibling) {
1840 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1841 }
1842
1843 LY_TREE_DFS_END(sibling, next, elem);
1844 }
1845 }
1846 } else if (r == 3) {
1847 /* "." */
1848 if (!*ret) {
1849 *ret = ly_set_new();
1850 LY_CHECK_ERR_RETURN(!*ret, LOGMEM, -1);
1851 ly_set_add(*ret, (void *)start_parent, LY_SET_OPT_USEASLIST);
1852 }
1853 ly_set_add(*ret, (void *)sibling, LY_SET_OPT_USEASLIST);
1854 if (all_desc) {
1855 LY_TREE_DFS_BEGIN(sibling, next, elem) {
1856 if (elem != sibling) {
1857 ly_set_add(*ret, (void *)elem, LY_SET_OPT_USEASLIST);
1858 }
1859
1860 LY_TREE_DFS_END(sibling, next, elem);
1861 }
1862 }
1863 } else {
1864 LOGINT;
1865 return -1;
1866 }
1867 }
1868
1869 /* skip predicate */
1870 if (extended && has_predicate) {
1871 while (id[0] == '[') {
1872 id = strchr(id, ']');
1873 if (!id) {
1874 LOGINT;
1875 return -1;
1876 }
1877 ++id;
1878 }
1879 }
1880
1881 if (nodeid_end && ((r == 0) || (r == 2) || (r == 3))) {
1882 return EXIT_SUCCESS;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001883 }
1884
1885 /* no match */
1886 if (!sibling) {
Michal Vaskobb520442017-05-23 10:55:18 +02001887 if (last_aug) {
1888 /* it still could be in another augment */
1889 goto get_next_augment;
1890 }
Michal Vasko50576712017-07-28 12:28:33 +02001891 if (no_node_error) {
1892 str = strndup(nodeid, (name - nodeid) + nam_len);
1893 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1894 free(str);
1895 return -1;
1896 }
Michal Vaskoa426fef2016-03-07 10:47:31 +01001897 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001898 return EXIT_SUCCESS;
1899 }
1900
Michal Vasko50576712017-07-28 12:28:33 +02001901 r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate,
1902 (extended ? &all_desc : NULL), extended);
1903 if (r < 1) {
1904 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[r], &id[r]);
1905 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001906 }
1907 id += r;
1908 }
1909
1910 /* cannot get here */
1911 LOGINT;
1912 return -1;
1913}
1914
Radek Krejcif3c71de2016-04-11 12:45:46 +02001915/* unique, refine,
1916 * >0 - unexpected char on position (ret - 1),
1917 * 0 - ok (but ret can still be NULL),
1918 * -1 - error,
1919 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001920int
1921resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Michal Vaskodc300b02017-04-07 14:09:20 +02001922 int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001923{
1924 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01001925 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001926 int r, nam_len, mod_name_len, is_relative = -1;
1927 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001928 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001929
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001930 assert(nodeid && ret);
Radek Krejcie2077412017-01-26 16:03:39 +01001931 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT | LYS_GROUPING)));
Michal Vasko3edeaf72016-02-11 13:17:43 +01001932
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01001933 if (!start) {
1934 /* leaf not found */
1935 return 0;
1936 }
1937
Michal Vasko3edeaf72016-02-11 13:17:43 +01001938 id = nodeid;
Michal Vasko50576712017-07-28 12:28:33 +02001939 module = lys_node_module(start);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001940
Michal Vasko50576712017-07-28 12:28:33 +02001941 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 +01001942 return ((id - nodeid) - r) + 1;
1943 }
1944 id += r;
1945
1946 if (!is_relative) {
1947 return -1;
1948 }
1949
Michal Vasko24476fa2017-03-08 12:33:48 +01001950 start_parent = lys_parent(start);
Michal Vasko74a991b2017-03-31 09:17:22 +02001951 while ((start_parent->nodetype == LYS_USES) && lys_parent(start_parent)) {
Michal Vasko24476fa2017-03-08 12:33:48 +01001952 start_parent = lys_parent(start_parent);
1953 }
1954
Michal Vasko3edeaf72016-02-11 13:17:43 +01001955 while (1) {
1956 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01001957 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko74a991b2017-03-31 09:17:22 +02001958 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_PARENTUSES))) {
Michal Vasko50576712017-07-28 12:28:33 +02001959 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
1960 if (r == 0) {
1961 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001962 if (!(sibling->nodetype & ret_nodetype)) {
1963 /* wrong node type, too bad */
1964 continue;
1965 }
1966 *ret = sibling;
1967 return EXIT_SUCCESS;
1968 }
Michal Vasko50576712017-07-28 12:28:33 +02001969 start_parent = sibling;
1970 break;
1971 } else if (r == 1) {
1972 continue;
1973 } else {
1974 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001975 }
1976 }
1977
1978 /* no match */
1979 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001980 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001981 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001982 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1983 *ret = NULL;
1984 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001985 }
1986
Michal Vasko50576712017-07-28 12:28:33 +02001987 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 +01001988 return ((id - nodeid) - r) + 1;
1989 }
1990 id += r;
1991 }
1992
1993 /* cannot get here */
1994 LOGINT;
1995 return -1;
1996}
1997
1998/* choice default */
1999int
2000resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
2001{
2002 /* cannot actually be a path */
2003 if (strchr(nodeid, '/')) {
2004 return -1;
2005 }
2006
Michal Vaskodc300b02017-04-07 14:09:20 +02002007 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002008}
2009
2010/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
2011static int
2012resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
2013{
2014 const struct lys_module *module;
2015 const char *mod_prefix, *name;
2016 int i, mod_prefix_len, nam_len;
2017
2018 /* parse the identifier, it must be parsed on one call */
Michal Vasko50576712017-07-28 12:28:33 +02002019 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 +01002020 return -i + 1;
2021 }
2022
2023 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
2024 if (!module) {
2025 return -1;
2026 }
Radek Krejci0a8205d2017-03-01 16:25:29 +01002027 if (module != lys_main_module(start->module)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002028 start = module->data;
2029 }
2030
2031 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
2032
2033 return EXIT_SUCCESS;
2034}
2035
2036int
2037resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
2038 const struct lys_node **ret)
2039{
2040 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002041 const struct lys_node *sibling, *start_parent;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002042 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcibdf92362016-04-08 14:43:34 +02002043 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002044
2045 assert(nodeid && module && ret);
2046 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
2047
2048 id = nodeid;
Michal Vasko24476fa2017-03-08 12:33:48 +01002049 start_parent = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002050
Michal Vasko50576712017-07-28 12:28:33 +02002051 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 +01002052 return ((id - nodeid) - r) + 1;
2053 }
2054 id += r;
2055
2056 if (is_relative) {
2057 return -1;
2058 }
2059
2060 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01002061 if (!abs_start_mod) {
2062 return -1;
2063 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002064
2065 while (1) {
2066 sibling = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01002067 while ((sibling = lys_getnext(sibling, start_parent, abs_start_mod, LYS_GETNEXT_WITHCHOICE
Michal Vasko3edeaf72016-02-11 13:17:43 +01002068 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
Michal Vasko50576712017-07-28 12:28:33 +02002069 r = schema_nodeid_siblingcheck(sibling, module, mod_name, mod_name_len, name, nam_len);
2070 if (r == 0) {
2071 if (!id[0]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002072 if (!(sibling->nodetype & ret_nodetype)) {
2073 /* wrong node type, too bad */
2074 continue;
2075 }
2076 *ret = sibling;
2077 return EXIT_SUCCESS;
2078 }
Michal Vasko50576712017-07-28 12:28:33 +02002079 start_parent = sibling;
2080 break;
2081 } else if (r == 1) {
2082 continue;
2083 } else {
2084 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002085 }
2086 }
2087
2088 /* no match */
2089 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01002090 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002091 return EXIT_SUCCESS;
2092 }
2093
Michal Vasko50576712017-07-28 12:28:33 +02002094 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 +01002095 return ((id - nodeid) - r) + 1;
2096 }
2097 id += r;
2098 }
2099
2100 /* cannot get here */
2101 LOGINT;
2102 return -1;
2103}
2104
Michal Vaskoe733d682016-03-14 09:08:27 +01002105static int
Michal Vasko50576712017-07-28 12:28:33 +02002106resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01002107{
Michal Vaskof359b022017-07-04 13:50:04 +02002108 const char *mod_name, *name;
2109 int mod_name_len, nam_len, has_predicate, i;
2110 struct lys_node *key;
Michal Vaskoe733d682016-03-14 09:08:27 +01002111
Michal Vaskof359b022017-07-04 13:50:04 +02002112 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 +02002113 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002114 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002115 return -1;
2116 }
2117
2118 predicate += i;
2119 *parsed += i;
2120
Michal Vasko58c2aab2017-01-05 10:02:05 +01002121 if (!isdigit(name[0])) {
2122 for (i = 0; i < list->keys_size; ++i) {
Michal Vaskof359b022017-07-04 13:50:04 +02002123 key = (struct lys_node *)list->keys[i];
2124 if (!strncmp(key->name, name, nam_len) && !key->name[nam_len]) {
Michal Vasko50576712017-07-28 12:28:33 +02002125 break;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002126 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002127 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002128
Michal Vasko58c2aab2017-01-05 10:02:05 +01002129 if (i == list->keys_size) {
2130 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2131 return -1;
2132 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002133 }
2134
2135 /* more predicates? */
2136 if (has_predicate) {
Michal Vasko50576712017-07-28 12:28:33 +02002137 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01002138 }
2139
2140 return 0;
2141}
2142
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002143/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01002144const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002145resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01002146{
Michal Vasko10728b52016-04-07 14:26:29 +02002147 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002148 const char *name, *mod_name, *id;
Michal Vasko24476fa2017-03-08 12:33:48 +01002149 const struct lys_node *sibling, *start_parent;
Michal Vaskodc300b02017-04-07 14:09:20 +02002150 int r, nam_len, mod_name_len, is_relative = -1, has_predicate;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002151 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vasko50576712017-07-28 12:28:33 +02002152 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002153
Michal Vasko3547c532016-03-14 09:40:50 +01002154 assert(nodeid && (ctx || start));
2155 if (!ctx) {
2156 ctx = start->module->ctx;
2157 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002158
2159 id = nodeid;
2160
Michal Vasko50576712017-07-28 12:28:33 +02002161 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 +01002162 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002163 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002164 }
2165 id += r;
2166
2167 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01002168 assert(start);
Michal Vasko24476fa2017-03-08 12:33:48 +01002169 start_parent = start;
2170 while (start_parent && (start_parent->nodetype == LYS_USES)) {
2171 start_parent = lys_parent(start_parent);
Michal Vasko3547c532016-03-14 09:40:50 +01002172 }
Michal Vasko50576712017-07-28 12:28:33 +02002173 module = start->module;
Michal Vasko3547c532016-03-14 09:40:50 +01002174 } else {
2175 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02002176 str = strndup(nodeid, (name + nam_len) - nodeid);
2177 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
2178 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002179 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02002180 } else if (mod_name_len > LY_BUF_SIZE - 1) {
2181 LOGINT;
2182 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002183 }
2184
Michal Vasko971a3ca2016-04-01 13:09:29 +02002185 if (ly_buf_used && module_name[0]) {
2186 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2187 }
2188 ly_buf_used++;
2189
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002190 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002191 module_name[mod_name_len] = '\0';
Michal Vasko50576712017-07-28 12:28:33 +02002192 module = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002193
2194 if (buf_backup) {
2195 /* return previous internal buffer content */
2196 strcpy(module_name, buf_backup);
2197 free(buf_backup);
2198 buf_backup = NULL;
2199 }
2200 ly_buf_used--;
2201
Michal Vasko50576712017-07-28 12:28:33 +02002202 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02002203 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2204 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2205 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01002206 return NULL;
2207 }
Michal Vasko24476fa2017-03-08 12:33:48 +01002208 start_parent = NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01002209
2210 /* now it's as if there was no module name */
2211 mod_name = NULL;
2212 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002213 }
2214
Michal Vasko50576712017-07-28 12:28:33 +02002215 prev_mod = module;
2216
Michal Vasko3edeaf72016-02-11 13:17:43 +01002217 while (1) {
2218 sibling = NULL;
Michal Vasko50576712017-07-28 12:28:33 +02002219 while ((sibling = lys_getnext(sibling, start_parent, module,
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002220 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002221 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002222 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002223 /* module check */
2224 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002225 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002226 LOGINT;
2227 return NULL;
2228 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002229
2230 if (ly_buf_used && module_name[0]) {
2231 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2232 }
2233 ly_buf_used++;
2234
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002235 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002236 module_name[mod_name_len] = '\0';
2237 /* will also find an augment module */
2238 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002239
2240 if (buf_backup) {
2241 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002242 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002243 free(buf_backup);
2244 buf_backup = NULL;
2245 }
2246 ly_buf_used--;
2247
Michal Vasko3edeaf72016-02-11 13:17:43 +01002248 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002249 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2250 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2251 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002252 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002253 }
2254 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002255 prefix_mod = prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002256 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002257 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002258 continue;
2259 }
2260
Michal Vaskoe733d682016-03-14 09:08:27 +01002261 /* do we have some predicates on it? */
2262 if (has_predicate) {
2263 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002264 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
Michal Vaskof359b022017-07-04 13:50:04 +02002265 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002266 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2267 return NULL;
2268 }
2269 } else if (sibling->nodetype == LYS_LIST) {
Michal Vasko50576712017-07-28 12:28:33 +02002270 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002271 return NULL;
2272 }
2273 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002274 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002275 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002276 }
2277 id += r;
2278 }
2279
Michal Vasko3edeaf72016-02-11 13:17:43 +01002280 /* the result node? */
2281 if (!id[0]) {
Michal Vaskoe733d682016-03-14 09:08:27 +01002282 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002283 }
2284
Michal Vaskodc300b02017-04-07 14:09:20 +02002285 /* move down the tree, if possible */
2286 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
2287 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2288 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002289 }
Michal Vaskodc300b02017-04-07 14:09:20 +02002290 start_parent = sibling;
Michal Vasko50576712017-07-28 12:28:33 +02002291
2292 /* update prev mod */
2293 prev_mod = (start_parent->child ? lys_node_module(start_parent->child) : module);
Michal Vasko3edeaf72016-02-11 13:17:43 +01002294 break;
2295 }
2296 }
2297
2298 /* no match */
2299 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002300 str = strndup(nodeid, (name + nam_len) - nodeid);
2301 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2302 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002303 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002304 }
2305
Michal Vasko50576712017-07-28 12:28:33 +02002306 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 +01002307 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002308 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002309 }
2310 id += r;
2311 }
2312
2313 /* cannot get here */
2314 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002315 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002316}
2317
Michal Vasko22448d32016-03-16 13:17:29 +01002318static int
Michal Vasko58c2aab2017-01-05 10:02:05 +01002319resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node,
Michal Vasko50576712017-07-28 12:28:33 +02002320 int position, int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002321{
Michal Vaskof359b022017-07-04 13:50:04 +02002322 const char *mod_name, *name, *value, *key_val;
2323 int mod_name_len, nam_len, val_len, has_predicate = 1, r;
Michal Vasko22448d32016-03-16 13:17:29 +01002324 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002325 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002326
Radek Krejci61a86c62016-03-24 11:06:44 +01002327 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002328 assert(node->schema->nodetype == LYS_LIST);
2329
Michal Vasko53adfc72017-01-06 10:39:10 +01002330 /* is the predicate a number? */
Michal Vaskof359b022017-07-04 13:50:04 +02002331 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 +01002332 || !strncmp(name, ".", nam_len)) {
2333 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
2334 return -1;
2335 }
2336
2337 if (isdigit(name[0])) {
2338 if (position == atoi(name)) {
2339 /* match */
2340 *parsed += r;
2341 return 0;
2342 } else {
2343 /* not a match */
2344 return 1;
2345 }
2346 }
2347
2348 if (!((struct lys_node_list *)node->schema)->keys_size) {
2349 /* no keys in schema - causes an error later */
2350 return 0;
2351 }
2352
Michal Vaskof29903d2016-04-18 13:13:10 +02002353 key = (struct lyd_node_leaf_list *)node->child;
Michal Vasko53adfc72017-01-06 10:39:10 +01002354 if (!key) {
2355 /* it is not a position, so we need a key for it to be a match */
2356 return 1;
2357 }
2358
2359 /* go through all the keys */
2360 i = 0;
2361 goto check_parsed_values;
2362
2363 for (; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
Michal Vasko22448d32016-03-16 13:17:29 +01002364 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002365 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002366 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002367 }
2368
Michal Vaskof359b022017-07-04 13:50:04 +02002369 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 +02002370 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002371 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002372 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002373 }
2374
Michal Vasko53adfc72017-01-06 10:39:10 +01002375check_parsed_values:
Michal Vasko22448d32016-03-16 13:17:29 +01002376 predicate += r;
2377 *parsed += r;
2378
Michal Vaskof29903d2016-04-18 13:13:10 +02002379 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002380 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002381 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002382 }
2383
Michal Vaskof359b022017-07-04 13:50:04 +02002384 if (mod_name) {
Michal Vasko50576712017-07-28 12:28:33 +02002385 /* specific module, check that the found key is from that module */
Michal Vaskof359b022017-07-04 13:50:04 +02002386 if (strncmp(lyd_node_module((struct lyd_node *)key)->name, mod_name, mod_name_len)
2387 || lyd_node_module((struct lyd_node *)key)->name[mod_name_len]) {
2388 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2389 return -1;
2390 }
Michal Vasko50576712017-07-28 12:28:33 +02002391
2392 /* but if the module is the same as the parent, it should have been omitted */
2393 if (lyd_node_module((struct lyd_node *)key) == lyd_node_module(node)) {
2394 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2395 return -1;
2396 }
Michal Vaskof359b022017-07-04 13:50:04 +02002397 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002398 /* no module, so it must be the same as the list (parent) */
2399 if (lyd_node_module((struct lyd_node *)key) != lyd_node_module(node)) {
Michal Vaskof359b022017-07-04 13:50:04 +02002400 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
2401 return -1;
2402 }
2403 }
2404
Michal Vasko9ba34de2016-12-07 12:21:19 +01002405 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002406 if ((key->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002407 && !strncmp(key->value_str, lyd_node_module(node)->name, strlen(lyd_node_module(node)->name))
2408 && (key->value_str[strlen(lyd_node_module(node)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002409 key_val = key->value_str + strlen(lyd_node_module(node)->name) + 1;
2410 } else {
2411 key_val = key->value_str;
2412 }
2413
Michal Vasko22448d32016-03-16 13:17:29 +01002414 /* value does not match */
Michal Vasko9ba34de2016-12-07 12:21:19 +01002415 if (strncmp(key_val, value, val_len) || key_val[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002416 return 1;
2417 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002418
2419 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002420 }
2421
2422 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002423 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002424 return -1;
2425 }
2426
2427 return 0;
2428}
2429
Radek Krejci45826012016-08-24 15:07:57 +02002430/**
2431 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2432 *
2433 * @param[in] nodeid Node data path to find
2434 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2435 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2436 * @param[out] parsed Number of characters processed in \p id
2437 * @return The closes parent (or the node itself) from the path
2438 */
Michal Vasko22448d32016-03-16 13:17:29 +01002439struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002440resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2441 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002442{
Michal Vasko10728b52016-04-07 14:26:29 +02002443 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002444 const char *id, *mod_name, *name, *pred_name, *data_val;
Michal Vasko58c2aab2017-01-05 10:02:05 +01002445 int r, ret, mod_name_len, nam_len, is_relative = -1, list_instance_position;
Michal Vasko9ba34de2016-12-07 12:21:19 +01002446 int has_predicate, last_parsed, llval_len, pred_name_len, last_has_pred;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002447 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002448 struct lyd_node_leaf_list *llist;
Michal Vasko50576712017-07-28 12:28:33 +02002449 const struct lys_module *prefix_mod, *prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002450 struct ly_ctx *ctx;
2451
2452 assert(nodeid && start && parsed);
2453
2454 ctx = start->schema->module->ctx;
2455 id = nodeid;
2456
Michal Vasko50576712017-07-28 12:28:33 +02002457 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 +01002458 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002459 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002460 return NULL;
2461 }
2462 id += r;
2463 /* add it to parsed only after the data node was actually found */
2464 last_parsed = r;
2465
2466 if (is_relative) {
Michal Vasko50576712017-07-28 12:28:33 +02002467 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002468 start = start->child;
2469 } else {
2470 for (; start->parent; start = start->parent);
Michal Vasko50576712017-07-28 12:28:33 +02002471 prev_mod = lyd_node_module(start);
Michal Vasko22448d32016-03-16 13:17:29 +01002472 }
2473
2474 while (1) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002475 list_instance_position = 0;
2476
Michal Vasko22448d32016-03-16 13:17:29 +01002477 LY_TREE_FOR(start, sibling) {
Michal Vasko945b96b2016-10-18 11:49:12 +02002478 /* RPC/action data check, return simply invalid argument, because the data tree is invalid */
Michal Vasko2411b942016-03-23 13:50:03 +01002479 if (lys_parent(sibling->schema)) {
2480 if (options & LYD_PATH_OPT_OUTPUT) {
2481 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002482 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002483 *parsed = -1;
2484 return NULL;
2485 }
2486 } else {
2487 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002488 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002489 *parsed = -1;
2490 return NULL;
2491 }
2492 }
2493 }
2494
Michal Vasko22448d32016-03-16 13:17:29 +01002495 /* name match */
2496 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2497
2498 /* module check */
2499 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002500 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002501 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002502 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002503 return NULL;
2504 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002505
2506 if (ly_buf_used && module_name[0]) {
2507 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2508 }
2509 ly_buf_used++;
2510
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002511 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002512 module_name[mod_name_len] = '\0';
2513 /* will also find an augment module */
2514 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002515
2516 if (buf_backup) {
2517 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002518 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002519 free(buf_backup);
2520 buf_backup = NULL;
2521 }
2522 ly_buf_used--;
2523
Michal Vasko22448d32016-03-16 13:17:29 +01002524 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002525 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2526 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2527 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002528 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002529 return NULL;
2530 }
2531 } else {
Michal Vasko50576712017-07-28 12:28:33 +02002532 prefix_mod = prev_mod;
Michal Vasko22448d32016-03-16 13:17:29 +01002533 }
Michal Vasko1adc7242016-11-16 11:05:28 +01002534 if (prefix_mod != lyd_node_module(sibling)) {
Michal Vasko22448d32016-03-16 13:17:29 +01002535 continue;
2536 }
2537
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002538 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002539 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002540 llist = (struct lyd_node_leaf_list *)sibling;
2541
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002542 last_has_pred = 0;
Michal Vaskof0a50972016-10-19 11:33:55 +02002543 if (has_predicate) {
Michal Vaskof359b022017-07-04 13:50:04 +02002544 if ((r = parse_schema_json_predicate(id, NULL, NULL, &pred_name, &pred_name_len, &llist_value,
2545 &llval_len, &last_has_pred)) < 1) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002546 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2547 *parsed = -1;
2548 return NULL;
2549 }
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002550 if ((pred_name[0] != '.') || (pred_name_len != 1)) {
2551 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[1], id + 1);
2552 *parsed = -1;
2553 return NULL;
2554 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002555 } else {
2556 r = 0;
2557 if (llist_value) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002558 llval_len = strlen(llist_value);
Michal Vaskof0a50972016-10-19 11:33:55 +02002559 }
2560 }
2561
Michal Vasko9ba34de2016-12-07 12:21:19 +01002562 /* make value canonical */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01002563 if ((llist->value_type & LY_TYPE_IDENT)
Michal Vasko6a938d62016-12-21 09:21:30 +01002564 && !strncmp(llist->value_str, lyd_node_module(sibling)->name, strlen(lyd_node_module(sibling)->name))
2565 && (llist->value_str[strlen(lyd_node_module(sibling)->name)] == ':')) {
Michal Vasko9ba34de2016-12-07 12:21:19 +01002566 data_val = llist->value_str + strlen(lyd_node_module(sibling)->name) + 1;
2567 } else {
2568 data_val = llist->value_str;
2569 }
2570
2571 if ((!llist_value && data_val && data_val[0])
2572 || (llist_value && (strncmp(llist_value, data_val, llval_len) || data_val[llval_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002573 continue;
2574 }
Michal Vasko9ba34de2016-12-07 12:21:19 +01002575
Michal Vaskof0a50972016-10-19 11:33:55 +02002576 id += r;
2577 last_parsed += r;
Michal Vasko0a8d17f2016-10-19 15:51:36 +02002578 has_predicate = last_has_pred;
Michal Vaskof0a50972016-10-19 11:33:55 +02002579
Radek Krejci45826012016-08-24 15:07:57 +02002580 } else if (sibling->schema->nodetype == LYS_LIST) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002581 /* 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 +01002582 if (!has_predicate) {
Michal Vasko58c2aab2017-01-05 10:02:05 +01002583 /* none match */
2584 return last_match;
Michal Vasko22448d32016-03-16 13:17:29 +01002585 }
Michal Vasko58c2aab2017-01-05 10:02:05 +01002586
2587 ++list_instance_position;
2588 r = 0;
Michal Vasko50576712017-07-28 12:28:33 +02002589 ret = resolve_partial_json_data_list_predicate(id, name, sibling, list_instance_position, &r);
Michal Vasko22448d32016-03-16 13:17:29 +01002590 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002591 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002592 return NULL;
2593 } else if (ret == 1) {
2594 /* this list instance does not match */
2595 continue;
2596 }
2597 id += r;
2598 last_parsed += r;
2599 }
2600
2601 *parsed += last_parsed;
2602
2603 /* the result node? */
2604 if (!id[0]) {
2605 return sibling;
2606 }
2607
2608 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002609 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002610 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002611 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002612 return NULL;
2613 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002614 last_match = sibling;
Michal Vasko50576712017-07-28 12:28:33 +02002615 prev_mod = lyd_node_module(sibling);
Michal Vasko22448d32016-03-16 13:17:29 +01002616 start = sibling->child;
Michal Vasko22448d32016-03-16 13:17:29 +01002617 break;
2618 }
2619 }
2620
2621 /* no match, return last match */
2622 if (!sibling) {
2623 return last_match;
2624 }
2625
Michal Vasko50576712017-07-28 12:28:33 +02002626 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 +01002627 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002628 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002629 return NULL;
2630 }
2631 id += r;
2632 last_parsed = r;
2633 }
2634
2635 /* cannot get here */
2636 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002637 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002638 return NULL;
2639}
2640
Michal Vasko3edeaf72016-02-11 13:17:43 +01002641/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002642 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002643 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002644 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002645 * @param[in] str_restr Restriction as a string.
2646 * @param[in] type Type of the restriction.
2647 * @param[out] ret Final interval structure that starts with
2648 * the interval of the initial type, continues with intervals
2649 * of any superior types derived from the initial one, and
2650 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002651 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002652 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002653 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002654int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002655resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002656{
2657 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002658 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002659 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002660 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002661 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002662 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002663 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002664
2665 switch (type->base) {
2666 case LY_TYPE_BINARY:
2667 kind = 0;
2668 local_umin = 0;
2669 local_umax = 18446744073709551615UL;
2670
2671 if (!str_restr && type->info.binary.length) {
2672 str_restr = type->info.binary.length->expr;
2673 }
2674 break;
2675 case LY_TYPE_DEC64:
2676 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002677 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2678 local_fmax = __INT64_C(9223372036854775807);
2679 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002680
2681 if (!str_restr && type->info.dec64.range) {
2682 str_restr = type->info.dec64.range->expr;
2683 }
2684 break;
2685 case LY_TYPE_INT8:
2686 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002687 local_smin = __INT64_C(-128);
2688 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002689
2690 if (!str_restr && type->info.num.range) {
2691 str_restr = type->info.num.range->expr;
2692 }
2693 break;
2694 case LY_TYPE_INT16:
2695 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002696 local_smin = __INT64_C(-32768);
2697 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002698
2699 if (!str_restr && type->info.num.range) {
2700 str_restr = type->info.num.range->expr;
2701 }
2702 break;
2703 case LY_TYPE_INT32:
2704 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002705 local_smin = __INT64_C(-2147483648);
2706 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002707
2708 if (!str_restr && type->info.num.range) {
2709 str_restr = type->info.num.range->expr;
2710 }
2711 break;
2712 case LY_TYPE_INT64:
2713 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002714 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2715 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002716
2717 if (!str_restr && type->info.num.range) {
2718 str_restr = type->info.num.range->expr;
2719 }
2720 break;
2721 case LY_TYPE_UINT8:
2722 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002723 local_umin = __UINT64_C(0);
2724 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002725
2726 if (!str_restr && type->info.num.range) {
2727 str_restr = type->info.num.range->expr;
2728 }
2729 break;
2730 case LY_TYPE_UINT16:
2731 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002732 local_umin = __UINT64_C(0);
2733 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002734
2735 if (!str_restr && type->info.num.range) {
2736 str_restr = type->info.num.range->expr;
2737 }
2738 break;
2739 case LY_TYPE_UINT32:
2740 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002741 local_umin = __UINT64_C(0);
2742 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002743
2744 if (!str_restr && type->info.num.range) {
2745 str_restr = type->info.num.range->expr;
2746 }
2747 break;
2748 case LY_TYPE_UINT64:
2749 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002750 local_umin = __UINT64_C(0);
2751 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002752
2753 if (!str_restr && type->info.num.range) {
2754 str_restr = type->info.num.range->expr;
2755 }
2756 break;
2757 case LY_TYPE_STRING:
2758 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002759 local_umin = __UINT64_C(0);
2760 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002761
2762 if (!str_restr && type->info.str.length) {
2763 str_restr = type->info.str.length->expr;
2764 }
2765 break;
2766 default:
2767 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002768 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002769 }
2770
2771 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002772 if (type->der) {
2773 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002774 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002775 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002776 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777 assert(!intv || (intv->kind == kind));
2778 }
2779
2780 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002781 /* we do not have any restriction, return superior ones */
2782 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002783 return EXIT_SUCCESS;
2784 }
2785
2786 /* adjust local min and max */
2787 if (intv) {
2788 tmp_intv = intv;
2789
2790 if (kind == 0) {
2791 local_umin = tmp_intv->value.uval.min;
2792 } else if (kind == 1) {
2793 local_smin = tmp_intv->value.sval.min;
2794 } else if (kind == 2) {
2795 local_fmin = tmp_intv->value.fval.min;
2796 }
2797
2798 while (tmp_intv->next) {
2799 tmp_intv = tmp_intv->next;
2800 }
2801
2802 if (kind == 0) {
2803 local_umax = tmp_intv->value.uval.max;
2804 } else if (kind == 1) {
2805 local_smax = tmp_intv->value.sval.max;
2806 } else if (kind == 2) {
2807 local_fmax = tmp_intv->value.fval.max;
2808 }
2809 }
2810
2811 /* finally parse our restriction */
2812 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002813 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002814 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002815 if (!tmp_local_intv) {
2816 assert(!local_intv);
2817 local_intv = malloc(sizeof *local_intv);
2818 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002819 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002820 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002821 tmp_local_intv = tmp_local_intv->next;
2822 }
Radek Krejcia8d111f2017-05-31 13:57:37 +02002823 LY_CHECK_ERR_GOTO(!tmp_local_intv, LOGMEM, error);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002824
2825 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002826 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002827 tmp_local_intv->next = NULL;
2828
2829 /* min */
2830 ptr = seg_ptr;
2831 while (isspace(ptr[0])) {
2832 ++ptr;
2833 }
2834 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2835 if (kind == 0) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002836 tmp_local_intv->value.uval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002837 } else if (kind == 1) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002838 tmp_local_intv->value.sval.min = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002839 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002840 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2841 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2842 goto error;
2843 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002844 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002845 } else if (!strncmp(ptr, "min", 3)) {
2846 if (kind == 0) {
2847 tmp_local_intv->value.uval.min = local_umin;
2848 } else if (kind == 1) {
2849 tmp_local_intv->value.sval.min = local_smin;
2850 } else if (kind == 2) {
2851 tmp_local_intv->value.fval.min = local_fmin;
2852 }
2853
2854 ptr += 3;
2855 } else if (!strncmp(ptr, "max", 3)) {
2856 if (kind == 0) {
2857 tmp_local_intv->value.uval.min = local_umax;
2858 } else if (kind == 1) {
2859 tmp_local_intv->value.sval.min = local_smax;
2860 } else if (kind == 2) {
2861 tmp_local_intv->value.fval.min = local_fmax;
2862 }
2863
2864 ptr += 3;
2865 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002866 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002867 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002868 }
2869
2870 while (isspace(ptr[0])) {
2871 ptr++;
2872 }
2873
2874 /* no interval or interval */
2875 if ((ptr[0] == '|') || !ptr[0]) {
2876 if (kind == 0) {
2877 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2878 } else if (kind == 1) {
2879 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2880 } else if (kind == 2) {
2881 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2882 }
2883 } else if (!strncmp(ptr, "..", 2)) {
2884 /* skip ".." */
2885 ptr += 2;
2886 while (isspace(ptr[0])) {
2887 ++ptr;
2888 }
2889
2890 /* max */
2891 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2892 if (kind == 0) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002893 tmp_local_intv->value.uval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002894 } else if (kind == 1) {
Radek Krejcif87f07d2017-07-11 10:53:16 +02002895 tmp_local_intv->value.sval.max = strtoll(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002896 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002897 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2898 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2899 goto error;
2900 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002901 }
2902 } else if (!strncmp(ptr, "max", 3)) {
2903 if (kind == 0) {
2904 tmp_local_intv->value.uval.max = local_umax;
2905 } else if (kind == 1) {
2906 tmp_local_intv->value.sval.max = local_smax;
2907 } else if (kind == 2) {
2908 tmp_local_intv->value.fval.max = local_fmax;
2909 }
2910 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002911 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002912 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002913 }
2914 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002915 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002916 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002917 }
2918
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002919 /* check min and max in correct order*/
2920 if (kind == 0) {
2921 /* current segment */
2922 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2923 goto error;
2924 }
2925 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2926 goto error;
2927 }
2928 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002929 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002930 goto error;
2931 }
2932 } else if (kind == 1) {
2933 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2934 goto error;
2935 }
2936 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2937 goto error;
2938 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002939 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002940 goto error;
2941 }
2942 } else if (kind == 2) {
2943 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2944 goto error;
2945 }
2946 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2947 goto error;
2948 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002949 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002950 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002951 goto error;
2952 }
2953 }
2954
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002955 /* next segment (next OR) */
2956 seg_ptr = strchr(seg_ptr, '|');
2957 if (!seg_ptr) {
2958 break;
2959 }
2960 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002961 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002962 }
2963
2964 /* check local restrictions against superior ones */
2965 if (intv) {
2966 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002967 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002968
2969 while (tmp_local_intv && tmp_intv) {
2970 /* reuse local variables */
2971 if (kind == 0) {
2972 local_umin = tmp_local_intv->value.uval.min;
2973 local_umax = tmp_local_intv->value.uval.max;
2974
2975 /* it must be in this interval */
2976 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2977 /* this interval is covered, next one */
2978 if (local_umax <= tmp_intv->value.uval.max) {
2979 tmp_local_intv = tmp_local_intv->next;
2980 continue;
2981 /* ascending order of restrictions -> fail */
2982 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002983 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002984 }
2985 }
2986 } else if (kind == 1) {
2987 local_smin = tmp_local_intv->value.sval.min;
2988 local_smax = tmp_local_intv->value.sval.max;
2989
2990 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2991 if (local_smax <= tmp_intv->value.sval.max) {
2992 tmp_local_intv = tmp_local_intv->next;
2993 continue;
2994 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002995 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002996 }
2997 }
2998 } else if (kind == 2) {
2999 local_fmin = tmp_local_intv->value.fval.min;
3000 local_fmax = tmp_local_intv->value.fval.max;
3001
Michal Vasko4d1f0482016-09-19 14:35:06 +02003002 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02003003 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02003004 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003005 tmp_local_intv = tmp_local_intv->next;
3006 continue;
3007 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003008 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003009 }
3010 }
3011 }
3012
3013 tmp_intv = tmp_intv->next;
3014 }
3015
3016 /* some interval left uncovered -> fail */
3017 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02003018 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003019 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003020 }
3021
Michal Vaskoaeb51802016-04-11 10:58:47 +02003022 /* append the local intervals to all the intervals of the superior types, return it all */
3023 if (intv) {
3024 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
3025 tmp_intv->next = local_intv;
3026 } else {
3027 intv = local_intv;
3028 }
3029 *ret = intv;
3030
3031 return EXIT_SUCCESS;
3032
3033error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003034 while (intv) {
3035 tmp_intv = intv->next;
3036 free(intv);
3037 intv = tmp_intv;
3038 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02003039 while (local_intv) {
3040 tmp_local_intv = local_intv->next;
3041 free(local_intv);
3042 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003043 }
3044
Michal Vaskoaeb51802016-04-11 10:58:47 +02003045 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02003046}
3047
Michal Vasko730dfdf2015-08-11 14:48:05 +02003048/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02003049 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
3050 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003051 *
3052 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02003053 * @param[in] mod_name Typedef name module name.
3054 * @param[in] module Main module.
3055 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003056 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003057 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003058 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003059 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003060int
Michal Vasko1e62a092015-12-01 12:27:20 +01003061resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
3062 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003063{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003064 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003065 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003066 int tpdf_size;
3067
Michal Vasko1dca6882015-10-22 14:29:42 +02003068 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003069 /* no prefix, try built-in types */
3070 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003071 if (!strcmp(ly_types[i]->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003072 if (ret) {
Radek Krejcia68ddeb2017-02-24 12:49:44 +01003073 *ret = ly_types[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003074 }
3075 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003076 }
3077 }
3078 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02003079 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003080 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02003081 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003082 }
3083 }
3084
Michal Vasko1dca6882015-10-22 14:29:42 +02003085 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003086 /* search in local typedefs */
3087 while (parent) {
3088 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02003089 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02003090 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
3091 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003092 break;
3093
Radek Krejci76512572015-08-04 09:47:08 +02003094 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02003095 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
3096 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097 break;
3098
Radek Krejci76512572015-08-04 09:47:08 +02003099 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02003100 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
3101 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003102 break;
3103
Radek Krejci76512572015-08-04 09:47:08 +02003104 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02003105 case LYS_ACTION:
3106 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
3107 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003108 break;
3109
Radek Krejci76512572015-08-04 09:47:08 +02003110 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02003111 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
3112 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003113 break;
3114
Radek Krejci76512572015-08-04 09:47:08 +02003115 case LYS_INPUT:
3116 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02003117 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
3118 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003119 break;
3120
3121 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02003122 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003123 continue;
3124 }
3125
3126 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003127 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003128 match = &tpdf[i];
3129 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003130 }
3131 }
3132
Michal Vaskodcf98e62016-05-05 17:53:53 +02003133 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003134 }
Radek Krejcic071c542016-01-27 14:57:51 +01003135 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003136 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02003137 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02003138 if (!module) {
3139 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140 }
3141 }
3142
3143 /* search in top level typedefs */
3144 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003145 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02003146 match = &module->tpdf[i];
3147 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003148 }
3149 }
3150
3151 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01003152 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003153 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02003154 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 +02003155 match = &module->inc[i].submodule->tpdf[j];
3156 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003157 }
3158 }
3159 }
3160
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003161 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02003162
3163check_leafref:
3164 if (ret) {
3165 *ret = match;
3166 }
3167 if (match->type.base == LY_TYPE_LEAFREF) {
3168 while (!match->type.info.lref.path) {
3169 match = match->type.der;
3170 assert(match);
3171 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02003172 }
3173 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003174}
3175
Michal Vasko1dca6882015-10-22 14:29:42 +02003176/**
3177 * @brief Check the default \p value of the \p type. Logs directly.
3178 *
3179 * @param[in] type Type definition to use.
3180 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01003181 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02003182 *
3183 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
3184 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003185static int
Radek Krejciab08f0f2017-03-09 16:37:15 +01003186check_default(struct lys_type *type, const char **value, struct lys_module *module, int tpdf)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003187{
Radek Krejcibad2f172016-08-02 11:04:15 +02003188 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02003189 struct lyd_node_leaf_list node;
Radek Krejci51673202016-11-01 17:00:32 +01003190 const char *dflt = NULL;
Radek Krejci9e6af732017-04-27 14:40:25 +02003191 char *s;
Radek Krejci37b756f2016-01-18 10:15:03 +01003192 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02003193
Radek Krejci51673202016-11-01 17:00:32 +01003194 assert(value);
3195
Radek Krejcic13db382016-08-16 10:52:42 +02003196 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02003197 /* the type was not resolved yet, nothing to do for now */
3198 return EXIT_FAILURE;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003199 } else if (!tpdf && !module->implemented) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003200 /* do not check defaults in not implemented module's data */
3201 return EXIT_SUCCESS;
Radek Krejci29eac3d2017-06-01 16:50:02 +02003202 } else if (tpdf && !module->implemented && type->base == LY_TYPE_IDENT) {
Radek Krejci9e6af732017-04-27 14:40:25 +02003203 /* identityrefs are checked when instantiated in data instead of typedef,
3204 * but in typedef the value has to be modified to include the prefix */
3205 if (*value) {
3206 if (strchr(*value, ':')) {
3207 dflt = transform_schema2json(module, *value);
3208 } else {
3209 /* default prefix of the module where the typedef is defined */
3210 asprintf(&s, "%s:%s", lys_main_module(module)->name, *value);
3211 dflt = lydict_insert_zc(module->ctx, s);
3212 }
3213 lydict_remove(module->ctx, *value);
3214 *value = dflt;
3215 }
3216 return EXIT_SUCCESS;
Radek Krejciab08f0f2017-03-09 16:37:15 +01003217 } else if (type->base == LY_TYPE_LEAFREF && tpdf) {
3218 /* leafref in typedef cannot be checked */
3219 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003220 }
3221
Radek Krejci51673202016-11-01 17:00:32 +01003222 dflt = *value;
3223 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003224 /* we do not have a new default value, so is there any to check even, in some base type? */
3225 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
3226 if (base_tpdf->dflt) {
Radek Krejci51673202016-11-01 17:00:32 +01003227 dflt = base_tpdf->dflt;
Michal Vasko478c4652016-07-21 12:55:01 +02003228 break;
3229 }
3230 }
3231
Radek Krejci51673202016-11-01 17:00:32 +01003232 if (!dflt) {
Michal Vasko478c4652016-07-21 12:55:01 +02003233 /* no default value, nothing to check, all is well */
3234 return EXIT_SUCCESS;
3235 }
3236
3237 /* 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)? */
3238 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02003239 case LY_TYPE_IDENT:
Radek Krejci9e6af732017-04-27 14:40:25 +02003240 if (lys_main_module(base_tpdf->type.parent->module)->implemented) {
3241 return EXIT_SUCCESS;
3242 } else {
3243 /* check the default value from typedef, but use also the typedef's module
3244 * due to possible searching in imported modules which is expected in
3245 * typedef's module instead of module where the typedef is used */
3246 module = base_tpdf->module;
3247 }
3248 break;
Michal Vasko478c4652016-07-21 12:55:01 +02003249 case LY_TYPE_INST:
3250 case LY_TYPE_LEAFREF:
3251 case LY_TYPE_BOOL:
3252 case LY_TYPE_EMPTY:
3253 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
3254 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02003255 case LY_TYPE_BITS:
3256 /* the default value must match the restricted list of values, if the type was restricted */
3257 if (type->info.bits.count) {
3258 break;
3259 }
3260 return EXIT_SUCCESS;
3261 case LY_TYPE_ENUM:
3262 /* the default value must match the restricted list of values, if the type was restricted */
3263 if (type->info.enums.count) {
3264 break;
3265 }
3266 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02003267 case LY_TYPE_DEC64:
3268 if (type->info.dec64.range) {
3269 break;
3270 }
3271 return EXIT_SUCCESS;
3272 case LY_TYPE_BINARY:
3273 if (type->info.binary.length) {
3274 break;
3275 }
3276 return EXIT_SUCCESS;
3277 case LY_TYPE_INT8:
3278 case LY_TYPE_INT16:
3279 case LY_TYPE_INT32:
3280 case LY_TYPE_INT64:
3281 case LY_TYPE_UINT8:
3282 case LY_TYPE_UINT16:
3283 case LY_TYPE_UINT32:
3284 case LY_TYPE_UINT64:
3285 if (type->info.num.range) {
3286 break;
3287 }
3288 return EXIT_SUCCESS;
3289 case LY_TYPE_STRING:
3290 if (type->info.str.length || type->info.str.patterns) {
3291 break;
3292 }
3293 return EXIT_SUCCESS;
3294 case LY_TYPE_UNION:
3295 /* way too much trouble learning whether we need to check the default again, so just do it */
3296 break;
3297 default:
3298 LOGINT;
3299 return -1;
3300 }
Radek Krejci55a161c2016-09-05 17:13:25 +02003301 } else if (type->base == LY_TYPE_EMPTY) {
3302 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
3303 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3304 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003305 }
3306
Michal Vasko1dca6882015-10-22 14:29:42 +02003307 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003308 memset(&node, 0, sizeof node);
Radek Krejci51673202016-11-01 17:00:32 +01003309 node.value_str = dflt;
Michal Vasko1dca6882015-10-22 14:29:42 +02003310 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003311 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Radek Krejcia8d111f2017-05-31 13:57:37 +02003312 LY_CHECK_ERR_RETURN(!node.schema, LOGMEM, -1);
Radek Krejcibad2f172016-08-02 11:04:15 +02003313 node.schema->name = strdup("fake-default");
Radek Krejcia8d111f2017-05-31 13:57:37 +02003314 LY_CHECK_ERR_RETURN(!node.schema->name, LOGMEM; free(node.schema), -1);
Michal Vasko56826402016-03-02 11:11:37 +01003315 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003316 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003317
Radek Krejci37b756f2016-01-18 10:15:03 +01003318 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003319 if (!type->info.lref.target) {
3320 ret = EXIT_FAILURE;
3321 goto finish;
3322 }
Radek Krejciab08f0f2017-03-09 16:37:15 +01003323 ret = check_default(&type->info.lref.target->type, &dflt, module, 0);
Radek Krejci51673202016-11-01 17:00:32 +01003324 if (!ret) {
3325 /* adopt possibly changed default value to its canonical form */
3326 if (*value) {
3327 *value = dflt;
3328 }
3329 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003330 } else {
Radek Krejcia571d942017-02-24 09:26:49 +01003331 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 +01003332 /* possible forward reference */
3333 ret = 1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003334 if (base_tpdf) {
Radek Krejci9ad23f42016-10-31 15:46:52 +01003335 /* default value is defined in some base typedef */
Radek Krejcibad2f172016-08-02 11:04:15 +02003336 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3337 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3338 /* we have refined bits/enums */
3339 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3340 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
Radek Krejci51673202016-11-01 17:00:32 +01003341 dflt, type->parent->name, base_tpdf->name);
Radek Krejcibad2f172016-08-02 11:04:15 +02003342 }
3343 }
Radek Krejci51673202016-11-01 17:00:32 +01003344 } else {
3345 /* success - adopt canonical form from the node into the default value */
3346 if (dflt != node.value_str) {
3347 /* this can happen only if we have non-inherited default value,
3348 * inherited default values are already in canonical form */
3349 assert(dflt == *value);
3350 *value = node.value_str;
3351 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003352 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003353 }
3354
3355finish:
3356 if (node.value_type == LY_TYPE_BITS) {
3357 free(node.value.bit);
3358 }
3359 free((char *)node.schema->name);
3360 free(node.schema);
3361
3362 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003363}
3364
Michal Vasko730dfdf2015-08-11 14:48:05 +02003365/**
3366 * @brief Check a key for mandatory attributes. Logs directly.
3367 *
3368 * @param[in] key The key to check.
3369 * @param[in] flags What flags to check.
3370 * @param[in] list The list of all the keys.
3371 * @param[in] index Index of the key in the key list.
3372 * @param[in] name The name of the keys.
3373 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003374 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003375 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003376 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003377static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003378check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379{
Radek Krejciadb57612016-02-16 13:34:34 +01003380 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 char *dup = NULL;
3382 int j;
3383
3384 /* existence */
3385 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003386 if (name[len] != '\0') {
3387 dup = strdup(name);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003388 LY_CHECK_ERR_RETURN(!dup, LOGMEM, -1);
Michal Vaskof02e3742015-08-05 16:27:02 +02003389 dup[len] = '\0';
3390 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003391 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003392 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003393 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003394 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003395 }
3396
3397 /* uniqueness */
3398 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003399 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003400 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003401 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
3403 }
3404
3405 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003406 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003407 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003408 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003409 }
3410
3411 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003412 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003413 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003414 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003415 }
3416
3417 /* config attribute is the same as of the list */
Radek Krejci5c08a992016-11-02 13:30:04 +01003418 if ((key->flags & LYS_CONFIG_MASK) && (list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003419 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003420 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003421 }
3422
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003423 /* key is not placed from augment */
3424 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003425 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01003426 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003427 return -1;
3428 }
3429
Radek Krejci3f21ada2016-08-01 13:34:31 +02003430 /* key is not when/if-feature -conditional */
3431 j = 0;
3432 if (key->when || (key->iffeature_size && (j = 1))) {
3433 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
Michal Vasko51e5c582017-01-19 14:16:39 +01003434 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Key definition cannot depend on a \"%s\" condition.",
Radek Krejci3f21ada2016-08-01 13:34:31 +02003435 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003436 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003437 }
3438
Michal Vasko0b85aa82016-03-07 14:37:43 +01003439 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003440}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003441
3442/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003443 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003444 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003446 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003447 *
3448 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3449 */
3450int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003451resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003452{
Radek Krejci581ce772015-11-10 17:22:40 +01003453 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003454 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003455
Michal Vaskodc300b02017-04-07 14:09:20 +02003456 rc = resolve_descendant_schema_nodeid(uniq_str_path, *lys_child(parent, LYS_LEAF), LYS_LEAF, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003457 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003458 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003459 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003460 if (rc > 0) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003461 LOGVAL(LYE_INCHAR, LY_VLOG_PREV, NULL, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003462 } else if (rc == -2) {
Michal Vasko51e5c582017-01-19 14:16:39 +01003463 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003464 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003465 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003466 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003467 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003468 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003469 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003470 }
Radek Krejci581ce772015-11-10 17:22:40 +01003471 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003472 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003473 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003474 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003475 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003476 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477 }
3478
Radek Krejcicf509982015-12-15 09:22:44 +01003479 /* check status */
Radek Krejcic3f1b6f2017-02-15 10:51:10 +01003480 if (parent->nodetype != LYS_EXT && lyp_check_status(parent->flags, parent->module, parent->name,
3481 leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003482 return -1;
3483 }
3484
Radek Krejcid09d1a52016-08-11 14:05:45 +02003485 /* check that all unique's targets are of the same config type */
3486 if (*trg_type) {
3487 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3488 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko51e5c582017-01-19 14:16:39 +01003489 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcid09d1a52016-08-11 14:05:45 +02003490 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3491 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3492 return -1;
3493 }
3494 } else {
3495 /* first unique */
3496 if (leaf->flags & LYS_CONFIG_W) {
3497 *trg_type = 1;
3498 } else {
3499 *trg_type = 2;
3500 }
3501 }
3502
Radek Krejcica7efb72016-01-18 13:06:01 +01003503 /* set leaf's unique flag */
3504 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3505
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 return EXIT_SUCCESS;
3507
3508error:
3509
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003510 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003511}
3512
Radek Krejci0c0086a2016-03-24 15:20:28 +01003513void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003514unres_data_del(struct unres_data *unres, uint32_t i)
3515{
3516 /* there are items after the one deleted */
3517 if (i+1 < unres->count) {
3518 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003519 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003520
3521 /* deleting the last item */
3522 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003523 free(unres->node);
3524 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003525 }
3526
3527 /* if there are no items after and it is not the last one, just move the counter */
3528 --unres->count;
3529}
3530
Michal Vasko0491ab32015-08-19 14:28:29 +02003531/**
3532 * @brief Resolve (find) a data node from a specific module. Does not log.
3533 *
3534 * @param[in] mod Module to search in.
3535 * @param[in] name Name of the data node.
3536 * @param[in] nam_len Length of the name.
3537 * @param[in] start Data node to start the search from.
3538 * @param[in,out] parents Resolved nodes. If there are some parents,
3539 * they are replaced (!!) with the resolvents.
3540 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003541 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003542 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003543static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003544resolve_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 +02003545{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003546 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003547 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003548 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003549
Michal Vasko23b61ec2015-08-19 11:19:50 +02003550 if (!parents->count) {
3551 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003552 parents->node = malloc(sizeof *parents->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003553 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02003554 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003555 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003556 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003557 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003558 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003559 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003560 continue;
3561 }
3562 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003563 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vasko39608352017-05-11 10:37:10 +02003564 if (lyd_node_module(node) == mod && !strncmp(node->schema->name, name, nam_len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003565 && node->schema->name[nam_len] == '\0') {
3566 /* matching target */
3567 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003568 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003569 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570 flag = 1;
3571 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003572 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003573 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003574 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02003575 LY_CHECK_ERR_RETURN(!parents->node, LOGMEM, EXIT_FAILURE);
Michal Vaskocf024702015-10-08 15:01:42 +02003576 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003577 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578 }
3579 }
3580 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003581
3582 if (!flag) {
3583 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003584 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003585 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003586 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003587 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003588 }
3589
Michal Vasko0491ab32015-08-19 14:28:29 +02003590 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003591}
3592
Michal Vaskoe27516a2016-10-10 17:55:31 +00003593static int
Michal Vasko1c007172017-03-10 10:20:44 +01003594resolve_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 +00003595{
3596 int dep1, dep2;
3597 const struct lys_node *node;
3598
3599 if (lys_parent(op_node)) {
3600 /* inner operation (notif/action) */
3601 if (abs_path) {
3602 return 1;
3603 } else {
3604 /* compare depth of both nodes */
3605 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3606 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3607 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3608 return 1;
3609 }
3610 }
3611 } else {
3612 /* top-level operation (notif/rpc) */
3613 if (op_node != first_node) {
3614 return 1;
3615 }
3616 }
3617
3618 return 0;
3619}
3620
Michal Vasko730dfdf2015-08-11 14:48:05 +02003621/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003622 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003623 *
Michal Vaskobb211122015-08-19 14:03:11 +02003624 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003625 * @param[in] context_node Predicate context node (where the predicate is placed).
3626 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003627 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003628 *
Michal Vasko184521f2015-09-24 13:14:26 +02003629 * @return 0 on forward reference, otherwise the number
3630 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003631 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003632 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003633static int
Michal Vasko1c007172017-03-10 10:20:44 +01003634resolve_schema_leafref_predicate(const char *path, const struct lys_node *context_node,
3635 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003636{
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003637 const struct lys_module *trg_mod;
Michal Vasko1e62a092015-12-01 12:27:20 +01003638 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003639 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003640 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, pke_parsed, parsed = 0;
3641 int has_predicate, dest_parent_times, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003642
3643 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003644 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003645 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003646 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 return -parsed+i;
3648 }
3649 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003650 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003651
Michal Vasko58090902015-08-13 14:04:15 +02003652 /* source (must be leaf) */
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003653 if (sour_pref) {
3654 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, sour_pref, sour_pref_len);
3655 } else {
3656 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003657 }
Michal Vaskobb520442017-05-23 10:55:18 +02003658 rc = lys_getnext_data(trg_mod, context_node, source, sour_len, LYS_LEAF | LYS_LEAFLIST, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003659 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003660 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003661 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003662 }
3663
3664 /* destination */
Michal Vaskof9b35d92016-10-21 15:19:30 +02003665 dest_parent_times = 0;
3666 pke_parsed = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003667 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3668 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003669 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 +02003670 return -parsed;
3671 }
3672 pke_parsed += i;
3673
Radek Krejciadb57612016-02-16 13:34:34 +01003674 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003675 if (dst_node->parent && (dst_node->parent->nodetype == LYS_AUGMENT)
3676 && !((struct lys_node_augment *)dst_node->parent)->target) {
3677 /* we are in an unresolved augment, cannot evaluate */
3678 LOGVAL(LYE_SPEC, LY_VLOG_LYS, dst_node->parent,
3679 "Cannot resolve leafref predicate \"%s\" because it is in an unresolved augment.", path_key_expr);
3680 return 0;
3681 }
3682
Michal Vaskofbaead72016-10-07 10:54:48 +02003683 /* path is supposed to be evaluated in data tree, so we have to skip
3684 * all schema nodes that cannot be instantiated in data tree */
3685 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003686 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003687 dst_node = lys_parent(dst_node));
3688
Michal Vasko1f76a282015-08-04 16:16:53 +02003689 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003690 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003691 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003692 }
3693 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003694 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003695 while (1) {
Michal Vasko0f99d3e2017-01-10 10:50:40 +01003696 if (dest_pref) {
3697 trg_mod = lys_get_import_module(lys_node_module(parent), NULL, 0, dest_pref, dest_pref_len);
3698 } else {
3699 trg_mod = NULL;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003700 }
Michal Vaskobb520442017-05-23 10:55:18 +02003701 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 +02003702 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003703 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003704 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003705 }
3706
Michal Vaskoe27516a2016-10-10 17:55:31 +00003707 if (first_iter) {
Michal Vasko1c007172017-03-10 10:20:44 +01003708 if (resolve_schema_leafref_valid_dep_flag(op_node, dst_node, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003709 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003710 }
3711 first_iter = 0;
3712 }
3713
Michal Vasko1f76a282015-08-04 16:16:53 +02003714 if (pke_len == pke_parsed) {
3715 break;
3716 }
3717
Michal Vaskobb520442017-05-23 10:55:18 +02003718 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 +02003719 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003720 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Michal Vaskobb520442017-05-23 10:55:18 +02003721 (path_key_expr + pke_parsed)[-i], (path_key_expr + pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003722 return -parsed;
3723 }
3724 pke_parsed += i;
3725 }
3726
3727 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003728 if (dst_node->nodetype != src_node->nodetype) {
Michal Vaskobb520442017-05-23 10:55:18 +02003729 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path - parsed);
Michal Vasko51e5c582017-01-19 14:16:39 +01003730 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Destination node is not a %s, but a %s.",
Michal Vasko59ad4582016-09-16 13:15:41 +02003731 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003732 return -parsed;
3733 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003734 } while (has_predicate);
3735
3736 return parsed;
3737}
3738
Michal Vasko730dfdf2015-08-11 14:48:05 +02003739/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003740 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003741 *
Michal Vaskobb211122015-08-19 14:03:11 +02003742 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003743 * @param[in] parent_node Parent of the leafref.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003744 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003745 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003746 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003747 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003748static int
Michal Vasko1c007172017-03-10 10:20:44 +01003749resolve_schema_leafref(const char *path, struct lys_node *parent, const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003750{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003751 const struct lys_node *node, *op_node = NULL;
Michal Vaskobb520442017-05-23 10:55:18 +02003752 struct lys_node_augment *last_aug;
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003753 const struct lys_module *tmp_mod, *cur_module;
Michal Vasko1f76a282015-08-04 16:16:53 +02003754 const char *id, *prefix, *name;
3755 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003756 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003757
Michal Vasko184521f2015-09-24 13:14:26 +02003758 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003759 parent_times = 0;
3760 id = path;
3761
Michal Vasko1c007172017-03-10 10:20:44 +01003762 /* find operation schema we are in */
3763 for (op_node = lys_parent(parent);
3764 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3765 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003766
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003767 cur_module = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003768 do {
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003769 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 +01003770 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003771 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003772 }
3773 id += i;
3774
Michal Vaskobb520442017-05-23 10:55:18 +02003775 /* get the current module */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003776 tmp_mod = prefix ? lys_get_import_module(cur_module, NULL, 0, prefix, pref_len) : cur_module;
3777 if (!tmp_mod) {
Michal Vaskobb520442017-05-23 10:55:18 +02003778 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
3779 return EXIT_FAILURE;
3780 }
3781 last_aug = NULL;
3782
Michal Vasko184521f2015-09-24 13:14:26 +02003783 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003784 if (parent_times == -1) {
Michal Vaskobb520442017-05-23 10:55:18 +02003785 /* use module data */
3786 node = NULL;
Radek Krejci990af1f2016-11-09 13:53:36 +01003787
Michal Vasko1f76a282015-08-04 16:16:53 +02003788 } else if (parent_times > 0) {
Michal Vaskobb520442017-05-23 10:55:18 +02003789 /* we are looking for the right parent */
3790 for (i = 0, node = parent; i < parent_times; i++) {
Michal Vasko3ba2d792017-07-10 15:14:43 +02003791 if (node->parent && (node->parent->nodetype == LYS_AUGMENT)
3792 && !((struct lys_node_augment *)node->parent)->target) {
3793 /* we are in an unresolved augment, cannot evaluate */
3794 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node->parent,
3795 "Cannot resolve leafref \"%s\" because it is in an unresolved augment.", path);
3796 return EXIT_FAILURE;
3797 }
3798
Radek Krejci3a5501d2016-07-18 22:03:34 +02003799 /* path is supposed to be evaluated in data tree, so we have to skip
3800 * all schema nodes that cannot be instantiated in data tree */
3801 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003802 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003803 node = lys_parent(node));
3804
Michal Vasko1f76a282015-08-04 16:16:53 +02003805 if (!node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003806 if (i == parent_times - 1) {
3807 /* top-level */
3808 break;
3809 }
3810
3811 /* higher than top-level */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003812 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003813 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003814 }
3815 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003816 } else {
3817 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003818 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003819 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003820 }
3821
Michal Vaskobb520442017-05-23 10:55:18 +02003822 /* find the next node (either in unconnected augment or as a schema sibling, node is NULL for top-level node -
3823 * - useless to search for that in augments) */
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003824 if (!tmp_mod->implemented && node) {
Michal Vaskobb520442017-05-23 10:55:18 +02003825get_next_augment:
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003826 last_aug = lys_getnext_target_aug(last_aug, tmp_mod, node);
Michal Vaskobb520442017-05-23 10:55:18 +02003827 }
3828
Michal Vasko3c60cbb2017-07-10 11:50:03 +02003829 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 +02003830 | LYS_CONTAINER | LYS_RPC | LYS_ACTION | LYS_NOTIF | LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA, &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003831 if (rc) {
Michal Vaskobb520442017-05-23 10:55:18 +02003832 if (last_aug) {
3833 goto get_next_augment;
3834 }
Michal Vasko1c007172017-03-10 10:20:44 +01003835 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003836 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003837 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003838
Michal Vaskoe27516a2016-10-10 17:55:31 +00003839 if (first_iter) {
3840 /* set external dependency flag, we can decide based on the first found node */
Michal Vasko1c007172017-03-10 10:20:44 +01003841 if (op_node && parent_times &&
3842 resolve_schema_leafref_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01003843 parent->flags |= LYS_LEAFREF_DEP;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003844 }
3845 first_iter = 0;
3846 }
3847
Michal Vasko1f76a282015-08-04 16:16:53 +02003848 if (has_predicate) {
3849 /* we have predicate, so the current result must be list */
3850 if (node->nodetype != LYS_LIST) {
Michal Vasko1c007172017-03-10 10:20:44 +01003851 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003852 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003853 }
3854
Michal Vasko1c007172017-03-10 10:20:44 +01003855 i = resolve_schema_leafref_predicate(id, node, parent, op_node);
Michal Vaskobb520442017-05-23 10:55:18 +02003856 if (!i) {
3857 return EXIT_FAILURE;
3858 } else if (i < 0) {
3859 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003860 }
3861 id += i;
Michal Vaskof9b35d92016-10-21 15:19:30 +02003862 has_predicate = 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003863 }
3864 } while (id[0]);
3865
Michal Vaskoca917682016-07-25 11:00:37 +02003866 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
Radek Krejci2a5a9602016-11-04 10:21:13 +01003867 if ((node->nodetype != LYS_LEAF) && (node->nodetype != LYS_LEAFLIST)) {
Michal Vasko1c007172017-03-10 10:20:44 +01003868 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko51e5c582017-01-19 14:16:39 +01003869 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 +02003870 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003871 }
3872
Radek Krejcicf509982015-12-15 09:22:44 +01003873 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003874 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003875 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003876 return -1;
3877 }
3878
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003879 if (ret) {
3880 *ret = node;
3881 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003882
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003883 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003884}
3885
Michal Vasko730dfdf2015-08-11 14:48:05 +02003886/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003887 * @brief Resolve instance-identifier predicate in JSON data format.
3888 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003889 *
Michal Vaskobb211122015-08-19 14:03:11 +02003890 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003891 * @param[in,out] node_match Nodes matching the restriction without
3892 * the predicate. Nodes not satisfying
3893 * the predicate are removed.
3894 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003895 * @return Number of characters successfully parsed,
3896 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003897 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003898static int
Michal Vasko1c007172017-03-10 10:20:44 +01003899resolve_instid_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003900{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003901 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003902 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003903 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003904 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003905 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003906
Michal Vasko1f2cc332015-08-19 11:18:32 +02003907 assert(pred && node_match->count);
3908
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003909 idx = -1;
3910 parsed = 0;
3911
Michal Vaskob2f40be2016-09-08 16:03:48 +02003912 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003913 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003914 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003915 return -parsed+i;
3916 }
3917 parsed += i;
3918 pred += i;
3919
3920 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003921 /* pos */
3922 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003923 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003924 } else if (name[0] != '.') {
3925 /* list keys */
3926 if (pred_iter < 0) {
3927 pred_iter = 1;
3928 } else {
3929 ++pred_iter;
3930 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003931 }
3932
Michal Vaskof2f28a12016-09-09 12:43:06 +02003933 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003934 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003935 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003936 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003937 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003938 goto remove_instid;
3939 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003940
3941 target = node_match->node[j];
3942 /* check the value */
3943 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3944 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3945 goto remove_instid;
3946 }
3947
3948 } else if (!value) {
3949 /* keyless list position */
3950 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3951 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3952 goto remove_instid;
3953 }
3954
3955 if (idx != cur_idx) {
3956 goto remove_instid;
3957 }
3958
3959 } else {
3960 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003961 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003962 goto remove_instid;
3963 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003964
3965 /* key module must match the list module */
3966 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3967 || node_match->node[j]->schema->module->name[mod_len]) {
3968 goto remove_instid;
3969 }
3970 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003971 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003972 if (!target) {
3973 goto remove_instid;
3974 }
3975 if ((struct lys_node_leaf *)target->schema !=
3976 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3977 goto remove_instid;
3978 }
3979
3980 /* check the value */
3981 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3982 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3983 goto remove_instid;
3984 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003985 }
3986
Michal Vaskob2f40be2016-09-08 16:03:48 +02003987 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003988 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003989 continue;
3990
3991remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003992 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003993 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003994 }
3995 } while (has_predicate);
3996
Michal Vaskob2f40be2016-09-08 16:03:48 +02003997 /* check that all list keys were specified */
3998 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003999 j = 0;
4000 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02004001 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
4002 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
4003 /* not enough predicates, just remove the list instance */
4004 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02004005 } else {
4006 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004007 }
4008 }
4009
4010 if (!node_match->count) {
4011 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
4012 }
4013 }
4014
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004015 return parsed;
4016}
4017
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004018int
Michal Vasko769f8032017-01-24 13:11:55 +01004019lys_check_xpath(struct lys_node *node, int check_place, int warn_on_fwd_ref)
Michal Vasko9e635ac2016-10-17 11:44:09 +02004020{
4021 struct lys_node *parent, *elem;
4022 struct lyxp_set set;
4023 uint32_t i;
Michal Vasko769f8032017-01-24 13:11:55 +01004024 int ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004025
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004026 if (check_place) {
4027 parent = node;
4028 while (parent) {
4029 if (parent->nodetype == LYS_GROUPING) {
4030 /* unresolved grouping, skip for now (will be checked later) */
Michal Vasko9e635ac2016-10-17 11:44:09 +02004031 return EXIT_SUCCESS;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004032 }
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004033 if (parent->nodetype == LYS_AUGMENT) {
4034 if (!((struct lys_node_augment *)parent)->target) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004035 /* unresolved augment, skip for now (will be checked later) */
4036 return EXIT_FAILURE;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004037 } else {
4038 parent = ((struct lys_node_augment *)parent)->target;
4039 continue;
4040 }
4041 }
4042 parent = parent->parent;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004043 }
Michal Vasko9e635ac2016-10-17 11:44:09 +02004044 }
4045
Michal Vasko769f8032017-01-24 13:11:55 +01004046 ret = lyxp_node_atomize(node, &set, warn_on_fwd_ref);
4047 if (ret == -1) {
4048 return -1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004049 }
4050
4051 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4052
4053 for (i = 0; i < set.used; ++i) {
4054 /* skip roots'n'stuff */
4055 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4056 /* XPath expression cannot reference "lower" status than the node that has the definition */
4057 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4058 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4059 return -1;
4060 }
4061
4062 if (parent) {
4063 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4064 if (!elem) {
4065 /* not in node's RPC or notification subtree, set the flag */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01004066 node->flags |= LYS_XPATH_DEP;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004067 break;
4068 }
4069 }
4070 }
4071 }
4072
4073 free(set.val.snodes);
Michal Vasko769f8032017-01-24 13:11:55 +01004074 return ret;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004075}
4076
Radek Krejcif71f48f2016-10-25 16:37:24 +02004077static int
4078check_leafref_config(struct lys_node_leaf *leaf, struct lys_type *type)
4079{
4080 int i;
4081
4082 if (type->base == LY_TYPE_LEAFREF) {
Radek Krejcic688ca02017-03-20 12:54:39 +01004083 if ((leaf->flags & LYS_CONFIG_W) && type->info.lref.target && type->info.lref.req != -1 &&
4084 (type->info.lref.target->flags & LYS_CONFIG_R)) {
Radek Krejcid831dd42017-03-16 12:59:30 +01004085 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 +02004086 strnodetype(leaf->nodetype), strnodetype(type->info.lref.target->nodetype));
4087 return -1;
4088 }
4089 /* we can skip the test in case the leafref is not yet resolved. In that case the test is done in the time
4090 * of leafref resolving (lys_leaf_add_leafref_target()) */
4091 } else if (type->base == LY_TYPE_UNION) {
4092 for (i = 0; i < type->info.uni.count; i++) {
4093 if (check_leafref_config(leaf, &type->info.uni.types[i])) {
4094 return -1;
4095 }
4096 }
4097 }
4098 return 0;
4099}
4100
Michal Vasko9e635ac2016-10-17 11:44:09 +02004101/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004102 * @brief Passes config flag down to children, skips nodes without config flags.
Michal Vasko44ab1462017-05-18 13:18:36 +02004103 * Logs.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004104 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004105 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004106 * @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 +02004107 * @param[in] flags Flags to assign to all the nodes.
Radek Krejcib3142312016-11-09 11:04:12 +01004108 * @param[in,out] unres List of unresolved items.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004109 *
4110 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004111 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004112int
4113inherit_config_flag(struct lys_node *node, int flags, int clear)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004114{
Radek Krejcif71f48f2016-10-25 16:37:24 +02004115 struct lys_node_leaf *leaf;
4116
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004117 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004118 LY_TREE_FOR(node, node) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004119 if (clear) {
4120 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004121 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004122 } else {
4123 if (node->flags & LYS_CONFIG_SET) {
4124 /* skip nodes with an explicit config value */
4125 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4126 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
Michal Vasko51e5c582017-01-19 14:16:39 +01004127 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "State nodes cannot have configuration nodes as children.");
Michal Vaskoe022a562016-09-27 14:24:15 +02004128 return -1;
4129 }
4130 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004131 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004132
4133 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4134 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4135 /* check that configuration lists have keys */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004136 if ((node->nodetype == LYS_LIST) && (node->flags & LYS_CONFIG_W)
4137 && !((struct lys_node_list *)node)->keys_size) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004138 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4139 return -1;
4140 }
4141 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004142 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004143 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004144 if (inherit_config_flag(node->child, flags, clear)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004145 return -1;
4146 }
Radek Krejcif71f48f2016-10-25 16:37:24 +02004147 } else if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
4148 leaf = (struct lys_node_leaf *)node;
4149 if (check_leafref_config(leaf, &leaf->type)) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02004150 return -1;
4151 }
4152 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004153 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004154
4155 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004156}
4157
Michal Vasko730dfdf2015-08-11 14:48:05 +02004158/**
Michal Vasko7178e692016-02-12 15:58:05 +01004159 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004160 *
Michal Vaskobb211122015-08-19 14:03:11 +02004161 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004162 * @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 +01004163 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004164 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004165 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004166 */
Michal Vasko7178e692016-02-12 15:58:05 +01004167static int
Radek Krejcib3142312016-11-09 11:04:12 +01004168resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004169{
Michal Vasko44ab1462017-05-18 13:18:36 +02004170 int rc;
Michal Vasko1d87a922015-08-21 12:57:16 +02004171 struct lys_node *sub;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004172 struct lys_module *mod;
Michal Vasko50576712017-07-28 12:28:33 +02004173 struct ly_set *set;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004174
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004175 assert(aug);
Radek Krejcidf46e222016-11-08 11:57:37 +01004176 mod = lys_main_module(aug->module);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004177
Michal Vaskobb520442017-05-23 10:55:18 +02004178 /* set it as not applied for now */
4179 aug->flags |= LYS_NOTAPPLIED;
4180
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004181 /* it can already be resolved in case we returned EXIT_FAILURE from if block below */
Michal Vasko44ab1462017-05-18 13:18:36 +02004182 if (!aug->target) {
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004183 /* resolve target node */
Michal Vasko50576712017-07-28 12:28:33 +02004184 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 +02004185 if (rc == -1) {
Michal Vasko50576712017-07-28 12:28:33 +02004186 LOGVAL(LYE_PATH, LY_VLOG_LYS, aug);
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004187 return -1;
4188 }
Michal Vasko50576712017-07-28 12:28:33 +02004189 if (!set) {
Michal Vasko9bf4aa02017-06-12 09:24:02 +02004190 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4191 return EXIT_FAILURE;
4192 }
Michal Vasko50576712017-07-28 12:28:33 +02004193 aug->target = set->set.s[0];
4194 ly_set_free(set);
Michal Vasko15b36692016-08-26 15:29:54 +02004195 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02004196
Michal Vaskod58d5962016-03-02 14:29:41 +01004197 /* check for mandatory nodes - if the target node is in another module
4198 * the added nodes cannot be mandatory
4199 */
Michal Vasko44ab1462017-05-18 13:18:36 +02004200 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug->target))
4201 && (rc = lyp_check_mandatory_augment(aug, aug->target))) {
Radek Krejcie00d2312016-08-12 15:27:49 +02004202 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004203 }
4204
Michal Vasko07e89ef2016-03-03 13:28:57 +01004205 /* check augment target type and then augment nodes type */
Michal Vasko44ab1462017-05-18 13:18:36 +02004206 if (aug->target->nodetype & (LYS_CONTAINER | LYS_LIST)) {
Michal Vaskodb017262017-01-24 13:10:04 +01004207 LY_TREE_FOR(aug->child, sub) {
4208 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES
4209 | LYS_CHOICE | LYS_ACTION | LYS_NOTIF))) {
4210 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4211 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004212 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vaskodb017262017-01-24 13:10:04 +01004213 return -1;
4214 }
4215 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004216 } else if (aug->target->nodetype & (LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004217 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004218 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004219 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004220 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004221 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004222 return -1;
4223 }
4224 }
Michal Vasko44ab1462017-05-18 13:18:36 +02004225 } else if (aug->target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004226 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004227 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004228 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
Michal Vasko51e5c582017-01-19 14:16:39 +01004229 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko44ab1462017-05-18 13:18:36 +02004230 strnodetype(aug->target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004231 return -1;
4232 }
4233 }
4234 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004235 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko44ab1462017-05-18 13:18:36 +02004236 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Invalid augment target node type \"%s\".", strnodetype(aug->target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004237 return -1;
4238 }
4239
Radek Krejcic071c542016-01-27 14:57:51 +01004240 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004241 LY_TREE_FOR(aug->child, sub) {
Michal Vasko44ab1462017-05-18 13:18:36 +02004242 if (lys_check_id(sub, aug->target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004243 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004244 }
4245 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004246
Michal Vasko44ab1462017-05-18 13:18:36 +02004247 if (!aug->child) {
4248 /* empty augment, nothing to connect, but it is techincally applied */
4249 LOGWRN("Augment \"%s\" without children.", aug->target_name);
4250 aug->flags &= ~LYS_NOTAPPLIED;
4251 } else if (mod->implemented && apply_aug(aug, unres)) {
4252 /* we tried to connect it, we failed */
4253 return -1;
Michal Vasko15b36692016-08-26 15:29:54 +02004254 }
4255
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004256 return EXIT_SUCCESS;
4257}
4258
Radek Krejcie534c132016-11-23 13:32:31 +01004259static int
Radek Krejcia7db9702017-01-20 12:55:14 +01004260resolve_extension(struct unres_ext *info, struct lys_ext_instance **ext, struct unres_schema *unres)
Radek Krejcie534c132016-11-23 13:32:31 +01004261{
4262 enum LY_VLOG_ELEM vlog_type;
4263 void *vlog_node;
4264 unsigned int i, j;
Radek Krejcie534c132016-11-23 13:32:31 +01004265 struct lys_ext *e;
PavolVicanc1807262017-01-31 18:00:27 +01004266 char *ext_name, *ext_prefix, *tmp;
Radek Krejcie534c132016-11-23 13:32:31 +01004267 struct lyxml_elem *next_yin, *yin;
Radek Krejcia7db9702017-01-20 12:55:14 +01004268 const struct lys_module *mod;
PavolVican22e88682017-02-14 22:38:18 +01004269 struct lys_ext_instance *tmp_ext;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004270 LYEXT_TYPE etype;
Radek Krejcie534c132016-11-23 13:32:31 +01004271
4272 switch (info->parent_type) {
Radek Krejci0aa821a2016-12-08 11:21:35 +01004273 case LYEXT_PAR_NODE:
Radek Krejcie534c132016-11-23 13:32:31 +01004274 vlog_node = info->parent;
4275 vlog_type = LY_VLOG_LYS;
4276 break;
Radek Krejci0aa821a2016-12-08 11:21:35 +01004277 case LYEXT_PAR_MODULE:
4278 case LYEXT_PAR_IMPORT:
4279 case LYEXT_PAR_INCLUDE:
Radek Krejcie534c132016-11-23 13:32:31 +01004280 vlog_node = NULL;
4281 vlog_type = LY_VLOG_LYS;
4282 break;
Radek Krejci43ce4b72017-01-04 11:02:38 +01004283 default:
Radek Krejcie534c132016-11-23 13:32:31 +01004284 vlog_node = NULL;
Radek Krejci6a7fedf2017-02-10 12:38:06 +01004285 vlog_type = LY_VLOG_NONE;
Radek Krejcie534c132016-11-23 13:32:31 +01004286 break;
4287 }
4288
4289 if (info->datatype == LYS_IN_YIN) {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004290 /* YIN */
4291
Radek Krejcie534c132016-11-23 13:32:31 +01004292 /* get the module where the extension is supposed to be defined */
Radek Krejcia7db9702017-01-20 12:55:14 +01004293 mod = lys_get_import_module_ns(info->mod, info->data.yin->ns->value);
Radek Krejcie534c132016-11-23 13:32:31 +01004294 if (!mod) {
4295 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
Radek Krejci2b999ac2017-01-18 16:22:12 +01004296 return EXIT_FAILURE;
Radek Krejcie534c132016-11-23 13:32:31 +01004297 }
4298
4299 /* find the extension definition */
4300 e = NULL;
4301 for (i = 0; i < mod->extensions_size; i++) {
4302 if (ly_strequal(mod->extensions[i].name, info->data.yin->name, 1)) {
4303 e = &mod->extensions[i];
4304 break;
4305 }
4306 }
4307 /* try submodules */
4308 for (j = 0; !e && j < mod->inc_size; j++) {
4309 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4310 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, info->data.yin->name, 1)) {
4311 e = &mod->inc[j].submodule->extensions[i];
4312 break;
4313 }
4314 }
4315 }
4316 if (!e) {
4317 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, info->data.yin->name);
4318 return EXIT_FAILURE;
4319 }
4320
4321 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
Radek Krejcie534c132016-11-23 13:32:31 +01004322
Radek Krejci72b35992017-01-04 16:27:44 +01004323 if (e->plugin && e->plugin->check_position) {
4324 /* common part - we have plugin with position checking function, use it first */
4325 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4326 /* extension is not allowed here */
4327 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
4328 return -1;
4329 }
4330 }
4331
Radek Krejci8d6b7422017-02-03 14:42:13 +01004332 /* extension type-specific part - allocation */
4333 if (e->plugin) {
4334 etype = e->plugin->type;
4335 } else {
4336 /* default type */
4337 etype = LYEXT_FLAG;
4338 }
4339 switch (etype) {
4340 case LYEXT_FLAG:
4341 (*ext) = calloc(1, sizeof(struct lys_ext_instance));
4342 break;
4343 case LYEXT_COMPLEX:
4344 (*ext) = calloc(1, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
4345 break;
4346 case LYEXT_ERR:
4347 /* we never should be here */
4348 LOGINT;
4349 return -1;
4350 }
Radek Krejcia8d111f2017-05-31 13:57:37 +02004351 LY_CHECK_ERR_RETURN(!*ext, LOGMEM, -1);
Radek Krejci8d6b7422017-02-03 14:42:13 +01004352
4353 /* common part for all extension types */
4354 (*ext)->def = e;
4355 (*ext)->parent = info->parent;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004356 (*ext)->parent_type = info->parent_type;
Radek Krejcifebdad72017-02-06 11:35:51 +01004357 (*ext)->insubstmt = info->substmt;
4358 (*ext)->insubstmt_index = info->substmt_index;
Radek Krejci8de8f612017-02-16 15:03:32 +01004359 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004360
4361 if (!(e->flags & LYS_YINELEM) && e->argument) {
4362 (*ext)->arg_value = lyxml_get_attr(info->data.yin, e->argument, NULL);
4363 if (!(*ext)->arg_value) {
4364 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, info->data.yin->name);
4365 return -1;
4366 }
4367 (*ext)->arg_value = lydict_insert(mod->ctx, (*ext)->arg_value, 0);
4368 }
4369
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004370 (*ext)->nodetype = LYS_EXT;
4371 (*ext)->module = info->mod;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004372
Radek Krejci8d6b7422017-02-03 14:42:13 +01004373 /* extension type-specific part - parsing content */
4374 switch (etype) {
4375 case LYEXT_FLAG:
Radek Krejci72b35992017-01-04 16:27:44 +01004376 LY_TREE_FOR_SAFE(info->data.yin->child, next_yin, yin) {
4377 if (!yin->ns) {
4378 /* garbage */
4379 lyxml_free(mod->ctx, yin);
4380 continue;
4381 } else if (!strcmp(yin->ns->value, LY_NSYIN)) {
4382 /* standard YANG statements are not expected here */
4383 LOGVAL(LYE_INCHILDSTMT, vlog_type, vlog_node, yin->name, info->data.yin->name);
4384 return -1;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004385 } else if (yin->ns == info->data.yin->ns &&
4386 (e->flags & LYS_YINELEM) && ly_strequal(yin->name, e->argument, 1)) {
Radek Krejci72b35992017-01-04 16:27:44 +01004387 /* we have the extension's argument */
Radek Krejci8d6b7422017-02-03 14:42:13 +01004388 if ((*ext)->arg_value) {
Radek Krejci72b35992017-01-04 16:27:44 +01004389 LOGVAL(LYE_TOOMANY, vlog_type, vlog_node, yin->name, info->data.yin->name);
Radek Krejcie534c132016-11-23 13:32:31 +01004390 return -1;
4391 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004392 (*ext)->arg_value = yin->content;
Radek Krejci72b35992017-01-04 16:27:44 +01004393 yin->content = NULL;
4394 lyxml_free(mod->ctx, yin);
4395 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004396 /* extension instance */
4397 if (lyp_yin_parse_subnode_ext(info->mod, *ext, LYEXT_PAR_EXTINST, yin,
4398 LYEXT_SUBSTMT_SELF, 0, unres)) {
4399 return -1;
4400 }
Radek Krejci72b35992017-01-04 16:27:44 +01004401
Radek Krejci72b35992017-01-04 16:27:44 +01004402 continue;
Radek Krejcie534c132016-11-23 13:32:31 +01004403 }
Radek Krejci72b35992017-01-04 16:27:44 +01004404 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004405 break;
4406 case LYEXT_COMPLEX:
Radek Krejcifebdad72017-02-06 11:35:51 +01004407 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004408 if (lyp_yin_parse_complex_ext(info->mod, (struct lys_ext_instance_complex*)(*ext), info->data.yin, unres)) {
4409 /* TODO memory cleanup */
Radek Krejci72b35992017-01-04 16:27:44 +01004410 return -1;
4411 }
Radek Krejci8d6b7422017-02-03 14:42:13 +01004412 break;
4413 default:
4414 break;
Radek Krejcie534c132016-11-23 13:32:31 +01004415 }
Radek Krejci72b35992017-01-04 16:27:44 +01004416
4417 /* TODO - lyext_check_result_clb, other than LYEXT_FLAG plugins */
4418
Radek Krejcie534c132016-11-23 13:32:31 +01004419 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01004420 /* YANG */
4421
PavolVicanc1807262017-01-31 18:00:27 +01004422 ext_prefix = (char *)(*ext)->def;
4423 tmp = strchr(ext_prefix, ':');
4424 if (!tmp) {
4425 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
PavolVican22e88682017-02-14 22:38:18 +01004426 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004427 }
4428 ext_name = tmp + 1;
Radek Krejcie534c132016-11-23 13:32:31 +01004429
PavolVicanc1807262017-01-31 18:00:27 +01004430 /* get the module where the extension is supposed to be defined */
4431 mod = lys_get_import_module(info->mod, ext_prefix, tmp - ext_prefix, NULL, 0);
4432 if (!mod) {
4433 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4434 return EXIT_FAILURE;
4435 }
4436
4437 /* find the extension definition */
4438 e = NULL;
4439 for (i = 0; i < mod->extensions_size; i++) {
4440 if (ly_strequal(mod->extensions[i].name, ext_name, 0)) {
4441 e = &mod->extensions[i];
4442 break;
4443 }
4444 }
4445 /* try submodules */
4446 for (j = 0; !e && j < mod->inc_size; j++) {
4447 for (i = 0; i < mod->inc[j].submodule->extensions_size; i++) {
4448 if (ly_strequal(mod->inc[j].submodule->extensions[i].name, ext_name, 0)) {
4449 e = &mod->inc[j].submodule->extensions[i];
4450 break;
4451 }
4452 }
4453 }
4454 if (!e) {
4455 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, ext_prefix);
4456 return EXIT_FAILURE;
4457 }
4458
4459 /* we have the extension definition, so now it cannot be forward referenced and error is always fatal */
4460
4461 if (e->plugin && e->plugin->check_position) {
4462 /* common part - we have plugin with position checking function, use it first */
4463 if ((*e->plugin->check_position)(info->parent, info->parent_type, info->substmt)) {
4464 /* extension is not allowed here */
4465 LOGVAL(LYE_INSTMT, vlog_type, vlog_node, e->name);
PavolVican22e88682017-02-14 22:38:18 +01004466 goto error;
PavolVicanc1807262017-01-31 18:00:27 +01004467 }
4468 }
4469
PavolVican22e88682017-02-14 22:38:18 +01004470 /* extension common part */
PavolVicanc1807262017-01-31 18:00:27 +01004471 (*ext)->flags &= ~LYEXT_OPT_YANG;
PavolVicanc1807262017-01-31 18:00:27 +01004472 (*ext)->def = e;
4473 (*ext)->parent = info->parent;
Radek Krejci8de8f612017-02-16 15:03:32 +01004474 (*ext)->ext_type = e->plugin ? e->plugin->type : LYEXT_FLAG;
PavolVican22e88682017-02-14 22:38:18 +01004475
PavolVicanb0d84102017-02-15 16:32:42 +01004476 if (e->argument && !(*ext)->arg_value) {
4477 LOGVAL(LYE_MISSARG, LY_VLOG_NONE, NULL, e->argument, ext_name);
4478 goto error;
4479 }
4480
Radek Krejci7f1d47e2017-04-12 15:29:02 +02004481 (*ext)->module = info->mod;
4482 (*ext)->nodetype = LYS_EXT;
Radek Krejci5138e9f2017-04-12 13:10:46 +02004483
PavolVican22e88682017-02-14 22:38:18 +01004484 /* extension type-specific part */
4485 if (e->plugin) {
4486 etype = e->plugin->type;
4487 } else {
4488 /* default type */
4489 etype = LYEXT_FLAG;
PavolVicanc1807262017-01-31 18:00:27 +01004490 }
PavolVican22e88682017-02-14 22:38:18 +01004491 switch (etype) {
4492 case LYEXT_FLAG:
4493 /* nothing change */
4494 break;
4495 case LYEXT_COMPLEX:
4496 tmp_ext = realloc(*ext, ((struct lyext_plugin_complex*)e->plugin)->instance_size);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004497 LY_CHECK_ERR_GOTO(!tmp_ext, LOGMEM, error);
PavolVican22e88682017-02-14 22:38:18 +01004498 memset((char *)tmp_ext + sizeof **ext, 0, ((struct lyext_plugin_complex*)e->plugin)->instance_size - sizeof **ext);
4499 (*ext) = tmp_ext;
PavolVican22e88682017-02-14 22:38:18 +01004500 ((struct lys_ext_instance_complex*)(*ext))->substmt = ((struct lyext_plugin_complex*)e->plugin)->substmt;
PavolVicana1e291f2017-02-19 16:07:12 +01004501 if (info->data.yang) {
4502 *tmp = ':';
PavolVicandb0e8172017-02-20 00:46:09 +01004503 if (yang_parse_ext_substatement(info->mod, unres, info->data.yang->ext_substmt, ext_prefix,
4504 (struct lys_ext_instance_complex*)(*ext))) {
4505 goto error;
4506 }
4507 if (yang_fill_extcomplex_module(info->mod->ctx, (struct lys_ext_instance_complex*)(*ext), ext_prefix,
4508 info->data.yang->ext_modules, info->mod->implemented)) {
PavolVicana1e291f2017-02-19 16:07:12 +01004509 goto error;
4510 }
PavolVicana3876672017-02-21 15:49:51 +01004511 }
4512 if (lyp_mand_check_ext((struct lys_ext_instance_complex*)(*ext), ext_prefix)) {
4513 goto error;
PavolVicana1e291f2017-02-19 16:07:12 +01004514 }
PavolVican22e88682017-02-14 22:38:18 +01004515 break;
4516 case LYEXT_ERR:
4517 /* we never should be here */
4518 LOGINT;
4519 goto error;
4520 }
4521
PavolVican22e88682017-02-14 22:38:18 +01004522 if (yang_check_ext_instance(info->mod, &(*ext)->ext, (*ext)->ext_size, *ext, unres)) {
4523 goto error;
4524 }
4525 free(ext_prefix);
Radek Krejcie534c132016-11-23 13:32:31 +01004526 }
4527
4528 return EXIT_SUCCESS;
PavolVican22e88682017-02-14 22:38:18 +01004529error:
4530 free(ext_prefix);
4531 return -1;
Radek Krejcie534c132016-11-23 13:32:31 +01004532}
4533
Michal Vasko730dfdf2015-08-11 14:48:05 +02004534/**
Pavol Vican855ca622016-09-05 13:07:54 +02004535 * @brief Resolve (find) choice default case. Does not log.
4536 *
4537 * @param[in] choic Choice to use.
4538 * @param[in] dflt Name of the default case.
4539 *
4540 * @return Pointer to the default node or NULL.
4541 */
4542static struct lys_node *
4543resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4544{
4545 struct lys_node *child, *ret;
4546
4547 LY_TREE_FOR(choic->child, child) {
4548 if (child->nodetype == LYS_USES) {
4549 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4550 if (ret) {
4551 return ret;
4552 }
4553 }
4554
4555 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004556 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004557 return child;
4558 }
4559 }
4560
4561 return NULL;
4562}
4563
4564/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004565 * @brief Resolve uses, apply augments, refines. Logs directly.
4566 *
Michal Vaskobb211122015-08-19 14:03:11 +02004567 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004568 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004569 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004570 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004571 */
Michal Vasko184521f2015-09-24 13:14:26 +02004572static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004573resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004574{
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004575 struct ly_ctx *ctx = uses->module->ctx; /* shortcut */
Pavol Vican855ca622016-09-05 13:07:54 +02004576 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004577 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004578 struct lys_node_leaflist *llist;
4579 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004580 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004581 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004582 struct lys_iffeature *iff, **old_iff;
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004583 int i, j, k, rc;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004584 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004585 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004586
Michal Vasko71e1aa82015-08-12 12:17:51 +02004587 assert(uses->grp);
Radek Krejci6ff885d2017-01-03 14:06:22 +01004588
Radek Krejci93def382017-05-24 15:33:48 +02004589 /* check that the grouping is resolved (no unresolved uses inside) */
4590 assert(!uses->grp->unres_count);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004591
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004592 if (!uses->grp->child) {
4593 /* grouping without children, warning was already displayed */
4594 return EXIT_SUCCESS;
4595 }
4596
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004597 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004598 LY_TREE_FOR(uses->grp->child, node_aux) {
Radek Krejcif0bb3602017-01-25 17:05:08 +01004599 if (node_aux->nodetype & LYS_GROUPING) {
4600 /* do not instantiate groupings from groupings */
4601 continue;
4602 }
Radek Krejci6ff885d2017-01-03 14:06:22 +01004603 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004604 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004605 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
Michal Vasko51e5c582017-01-19 14:16:39 +01004606 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004607 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004608 }
Pavol Vican55abd332016-07-12 15:54:49 +02004609 /* test the name of siblings */
Radek Krejcif95b6292017-02-13 15:57:37 +01004610 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 +02004611 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004612 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004613 }
4614 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004615 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004616
Michal Vaskodef0db12015-10-07 13:22:48 +02004617 /* we managed to copy the grouping, the rest must be possible to resolve */
4618
Pavol Vican855ca622016-09-05 13:07:54 +02004619 if (uses->refine_size) {
4620 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004621 LY_CHECK_ERR_GOTO(!refine_nodes, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004622 }
4623
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004624 /* apply refines */
4625 for (i = 0; i < uses->refine_size; i++) {
4626 rfn = &uses->refine[i];
Radek Krejcie2077412017-01-26 16:03:39 +01004627 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child,
4628 LYS_NO_RPC_NOTIF_NODE | LYS_ACTION | LYS_NOTIF,
Michal Vaskodc300b02017-04-07 14:09:20 +02004629 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004630 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004631 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004632 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004633 }
4634
Radek Krejci1d82ef62015-08-07 14:44:40 +02004635 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004636 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004637 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004638 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004639 }
Pavol Vican855ca622016-09-05 13:07:54 +02004640 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004641
4642 /* description on any nodetype */
4643 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004644 lydict_remove(ctx, node->dsc);
4645 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004646 }
4647
4648 /* reference on any nodetype */
4649 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004650 lydict_remove(ctx, node->ref);
4651 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004652 }
4653
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004654 /* config on any nodetype,
4655 * in case of notification or rpc/action, the config is not applicable (there is no config status) */
4656 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004657 node->flags &= ~LYS_CONFIG_MASK;
4658 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004659 }
4660
4661 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004662 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004663 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004664 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004665 leaf = (struct lys_node_leaf *)node;
4666
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004667 /* replace default value */
Radek Krejci200bf712016-08-16 17:11:04 +02004668 lydict_remove(ctx, leaf->dflt);
4669 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4670
4671 /* check the default value */
Radek Krejci51673202016-11-01 17:00:32 +01004672 if (unres_schema_add_node(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT,
4673 (struct lys_node *)(&leaf->dflt)) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004674 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004675 }
Radek Krejci200bf712016-08-16 17:11:04 +02004676 } else if (node->nodetype == LYS_LEAFLIST) {
4677 /* leaf-list */
4678 llist = (struct lys_node_leaflist *)node;
4679
4680 /* remove complete set of defaults in target */
Radek Krejci542ab142017-01-23 15:57:08 +01004681 for (j = 0; j < llist->dflt_size; j++) {
4682 lydict_remove(ctx, llist->dflt[j]);
Radek Krejci200bf712016-08-16 17:11:04 +02004683 }
4684 free(llist->dflt);
4685
4686 /* copy the default set from refine */
Radek Krejcia8d111f2017-05-31 13:57:37 +02004687 llist->dflt = malloc(rfn->dflt_size * sizeof *llist->dflt);
4688 LY_CHECK_ERR_GOTO(!llist->dflt, LOGMEM, fail);
Radek Krejci200bf712016-08-16 17:11:04 +02004689 llist->dflt_size = rfn->dflt_size;
Radek Krejci542ab142017-01-23 15:57:08 +01004690 for (j = 0; j < llist->dflt_size; j++) {
4691 llist->dflt[j] = lydict_insert(ctx, rfn->dflt[j], 0);
Radek Krejci200bf712016-08-16 17:11:04 +02004692 }
4693
4694 /* check default value */
Radek Krejci542ab142017-01-23 15:57:08 +01004695 for (j = 0; j < llist->dflt_size; j++) {
Radek Krejci51673202016-11-01 17:00:32 +01004696 if (unres_schema_add_node(llist->module, unres, &llist->type, UNRES_TYPE_DFLT,
Radek Krejci542ab142017-01-23 15:57:08 +01004697 (struct lys_node *)(&llist->dflt[j])) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004698 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004699 }
4700 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004701 }
4702 }
4703
4704 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004705 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf285832017-01-26 16:05:41 +01004706 /* remove current value */
4707 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004708
Radek Krejcibf285832017-01-26 16:05:41 +01004709 /* set new value */
4710 node->flags |= (rfn->flags & LYS_MAND_MASK);
4711
Pavol Vican855ca622016-09-05 13:07:54 +02004712 if (rfn->flags & LYS_MAND_TRUE) {
4713 /* check if node has default value */
4714 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004715 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4716 "The \"mandatory\" statement is forbidden on leaf with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004717 goto fail;
4718 }
4719 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004720 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4721 "The \"mandatory\" statement is forbidden on choices with \"default\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004722 goto fail;
4723 }
4724 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004725 }
4726
4727 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004728 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4729 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4730 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004731 }
4732
4733 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004734 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004735 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004736 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004737 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004738 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004739 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004740 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004741 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004742 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004743 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004744 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004745 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004746 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004747 }
4748 }
4749
4750 /* must in leaf, leaf-list, list, container or anyxml */
4751 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004752 switch (node->nodetype) {
4753 case LYS_LEAF:
4754 old_size = &((struct lys_node_leaf *)node)->must_size;
4755 old_must = &((struct lys_node_leaf *)node)->must;
4756 break;
4757 case LYS_LEAFLIST:
4758 old_size = &((struct lys_node_leaflist *)node)->must_size;
4759 old_must = &((struct lys_node_leaflist *)node)->must;
4760 break;
4761 case LYS_LIST:
4762 old_size = &((struct lys_node_list *)node)->must_size;
4763 old_must = &((struct lys_node_list *)node)->must;
4764 break;
4765 case LYS_CONTAINER:
4766 old_size = &((struct lys_node_container *)node)->must_size;
4767 old_must = &((struct lys_node_container *)node)->must;
4768 break;
4769 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004770 case LYS_ANYDATA:
4771 old_size = &((struct lys_node_anydata *)node)->must_size;
4772 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004773 break;
4774 default:
4775 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004776 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004777 }
4778
4779 size = *old_size + rfn->must_size;
4780 must = realloc(*old_must, size * sizeof *rfn->must);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004781 LY_CHECK_ERR_GOTO(!must, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004782 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
Radek Krejci7f0164a2017-01-25 17:04:06 +01004783 must[j].ext_size = rfn->must[k].ext_size;
Radek Krejci8d6b7422017-02-03 14:42:13 +01004784 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 +02004785 &must[j].ext, 0, unres);
Pavol Vican855ca622016-09-05 13:07:54 +02004786 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4787 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4788 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4789 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4790 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004791 }
4792
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004793 *old_must = must;
4794 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004795
4796 /* check XPath dependencies again */
4797 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4798 goto fail;
4799 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004800 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004801
4802 /* if-feature in leaf, leaf-list, list, container or anyxml */
4803 if (rfn->iffeature_size) {
4804 old_size = &node->iffeature_size;
4805 old_iff = &node->iffeature;
4806
4807 size = *old_size + rfn->iffeature_size;
4808 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004809 LY_CHECK_ERR_GOTO(!iff, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004810 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4811 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004812 if (usize1) {
4813 /* there is something to duplicate */
4814 /* duplicate compiled expression */
4815 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4816 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004817 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004818 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004819
4820 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004821 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
Radek Krejcia8d111f2017-05-31 13:57:37 +02004822 LY_CHECK_ERR_GOTO(!iff[j].expr, LOGMEM, fail);
Pavol Vican855ca622016-09-05 13:07:54 +02004823 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004824 }
4825 }
4826
4827 *old_iff = iff;
4828 *old_size = size;
4829 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004830 }
4831
4832 /* apply augments */
4833 for (i = 0; i < uses->augment_size; i++) {
Radek Krejcib3142312016-11-09 11:04:12 +01004834 rc = resolve_augment(&uses->augment[i], uses->child, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004835 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004836 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004837 }
4838 }
4839
Pavol Vican855ca622016-09-05 13:07:54 +02004840 /* check refines */
4841 for (i = 0; i < uses->refine_size; i++) {
4842 node = refine_nodes[i];
4843 rfn = &uses->refine[i];
4844
4845 /* config on any nodetype */
Radek Krejcid2ac35f2016-10-21 23:08:28 +02004846 if ((rfn->flags & LYS_CONFIG_MASK) && (node->flags & LYS_CONFIG_MASK)) {
Pavol Vican855ca622016-09-05 13:07:54 +02004847 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
Radek Krejci5c08a992016-11-02 13:30:04 +01004848 if (parent && parent->nodetype != LYS_GROUPING && (parent->flags & LYS_CONFIG_MASK) &&
Pavol Vican855ca622016-09-05 13:07:54 +02004849 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4850 (rfn->flags & LYS_CONFIG_W)) {
4851 /* setting config true under config false is prohibited */
4852 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004853 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004854 "changing config from 'false' to 'true' is prohibited while "
4855 "the target's parent is still config 'false'.");
4856 goto fail;
4857 }
4858
4859 /* inherit config change to the target children */
4860 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4861 if (rfn->flags & LYS_CONFIG_W) {
4862 if (iter->flags & LYS_CONFIG_SET) {
4863 /* config is set explicitely, go to next sibling */
4864 next = NULL;
4865 goto nextsibling;
4866 }
4867 } else { /* LYS_CONFIG_R */
4868 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4869 /* error - we would have config data under status data */
4870 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
Michal Vasko51e5c582017-01-19 14:16:39 +01004871 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004872 "changing config from 'true' to 'false' is prohibited while the target "
4873 "has still a children with explicit config 'true'.");
4874 goto fail;
4875 }
4876 }
4877 /* change config */
4878 iter->flags &= ~LYS_CONFIG_MASK;
4879 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4880
4881 /* select next iter - modified LY_TREE_DFS_END */
4882 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4883 next = NULL;
4884 } else {
4885 next = iter->child;
4886 }
4887nextsibling:
4888 if (!next) {
4889 /* try siblings */
4890 next = iter->next;
4891 }
4892 while (!next) {
4893 /* parent is already processed, go to its sibling */
4894 iter = lys_parent(iter);
4895
4896 /* no siblings, go back through parents */
4897 if (iter == node) {
4898 /* we are done, no next element to process */
4899 break;
4900 }
4901 next = iter->next;
4902 }
4903 }
4904 }
4905
4906 /* default value */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004907 if (rfn->dflt_size) {
4908 if (node->nodetype == LYS_CHOICE) {
4909 /* choice */
4910 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4911 rfn->dflt[0]);
4912 if (!((struct lys_node_choice *)node)->dflt) {
4913 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4914 goto fail;
4915 }
4916 if (lyp_check_mandatory_choice(node)) {
4917 goto fail;
4918 }
Pavol Vican855ca622016-09-05 13:07:54 +02004919 }
4920 }
4921
4922 /* min/max-elements on list or leaf-list */
Radek Krejci2d3c8112017-04-19 10:20:50 +02004923 if (node->nodetype == LYS_LIST && ((struct lys_node_list *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004924 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004925 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4926 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004927 goto fail;
4928 }
Radek Krejci2d3c8112017-04-19 10:20:50 +02004929 } else if (node->nodetype == LYS_LEAFLIST && ((struct lys_node_leaflist *)node)->max) {
Pavol Vican855ca622016-09-05 13:07:54 +02004930 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004931 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4932 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, "\"min-elements\" is bigger than \"max-elements\".");
Pavol Vican855ca622016-09-05 13:07:54 +02004933 goto fail;
4934 }
4935 }
4936
4937 /* additional checks */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004938 /* default value with mandatory/min-elements */
Pavol Vican855ca622016-09-05 13:07:54 +02004939 if (node->nodetype == LYS_LEAFLIST) {
4940 llist = (struct lys_node_leaflist *)node;
4941 if (llist->dflt_size && llist->min) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004942 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "min-elements", "refine");
4943 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Pavol Vican855ca622016-09-05 13:07:54 +02004944 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4945 goto fail;
4946 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004947 } else if (node->nodetype == LYS_LEAF) {
4948 leaf = (struct lys_node_leaf *)node;
4949 if (leaf->dflt && (leaf->flags & LYS_MAND_TRUE)) {
Radek Krejcibdcaf242017-04-19 10:29:47 +02004950 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, uses, rfn->dflt_size ? "default" : "mandatory", "refine");
4951 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004952 "The \"mandatory\" statement is forbidden on leafs with the \"default\" statement.");
4953 goto fail;
4954 }
Pavol Vican855ca622016-09-05 13:07:54 +02004955 }
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004956
Pavol Vican855ca622016-09-05 13:07:54 +02004957 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
Radek Krejci4c5fbd32016-10-25 15:14:23 +02004958 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
Pavol Vican855ca622016-09-05 13:07:54 +02004959 for (parent = node->parent;
4960 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4961 parent = parent->parent) {
4962 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4963 /* stop also on presence containers */
4964 break;
4965 }
4966 }
4967 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4968 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4969 if (lyp_check_mandatory_choice(parent)) {
4970 goto fail;
4971 }
4972 }
4973 }
4974 }
4975 free(refine_nodes);
4976
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004977 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004978
4979fail:
4980 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4981 lys_node_free(iter, NULL, 0);
4982 }
Pavol Vican855ca622016-09-05 13:07:54 +02004983 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004984 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004985}
4986
Radek Krejci83a4bac2017-02-07 15:53:04 +01004987void
4988resolve_identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
Radek Krejci018f1f52016-08-03 16:01:20 +02004989{
4990 int i;
4991
4992 assert(der && base);
4993
Radek Krejci018f1f52016-08-03 16:01:20 +02004994 if (!base->der) {
Radek Krejci85a54be2016-10-20 12:39:56 +02004995 /* create a set for backlinks if it does not exist */
4996 base->der = ly_set_new();
Radek Krejci018f1f52016-08-03 16:01:20 +02004997 }
Radek Krejci85a54be2016-10-20 12:39:56 +02004998 /* store backlink */
4999 ly_set_add(base->der, der, LY_SET_OPT_USEASLIST);
Radek Krejci018f1f52016-08-03 16:01:20 +02005000
Radek Krejci85a54be2016-10-20 12:39:56 +02005001 /* do it recursively */
Radek Krejci018f1f52016-08-03 16:01:20 +02005002 for (i = 0; i < base->base_size; i++) {
Radek Krejci83a4bac2017-02-07 15:53:04 +01005003 resolve_identity_backlink_update(der, base->base[i]);
Radek Krejci018f1f52016-08-03 16:01:20 +02005004 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005005}
5006
Michal Vasko730dfdf2015-08-11 14:48:05 +02005007/**
5008 * @brief Resolve base identity recursively. Does not log.
5009 *
5010 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005011 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005012 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005013 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005014 *
Radek Krejci219fa612016-08-15 10:36:51 +02005015 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005016 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005017static int
Michal Vasko1e62a092015-12-01 12:27:20 +01005018resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02005019 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005020{
Michal Vaskof02e3742015-08-05 16:27:02 +02005021 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02005022 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005023
Radek Krejcicf509982015-12-15 09:22:44 +01005024 assert(ret);
5025
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005026 /* search module */
5027 for (i = 0; i < module->ident_size; i++) {
5028 if (!strcmp(basename, module->ident[i].name)) {
5029
5030 if (!ident) {
5031 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005032 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01005033 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005034 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005035 }
5036
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005037 base = &module->ident[i];
5038 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005039 }
5040 }
5041
5042 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005043 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
5044 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
5045 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005046
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005047 if (!ident) {
5048 *ret = &module->inc[j].submodule->ident[i];
5049 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005050 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005051
5052 base = &module->inc[j].submodule->ident[i];
5053 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005054 }
5055 }
5056 }
5057
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01005058matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005059 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01005060 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005061 /* is it already completely resolved? */
5062 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02005063 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02005064 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
5065
5066 /* simple check for circular reference,
5067 * the complete check is done as a side effect of using only completely
5068 * resolved identities (previous check of unres content) */
5069 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
5070 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
5071 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02005072 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02005073 }
5074
Radek Krejci06f64ed2016-08-15 11:07:44 +02005075 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01005076 }
5077 }
Radek Krejci018f1f52016-08-03 16:01:20 +02005078
Radek Krejcibabbff82016-02-19 13:31:37 +01005079 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02005080 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02005081 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005082 }
5083
Radek Krejci219fa612016-08-15 10:36:51 +02005084 /* base not found (maybe a forward reference) */
5085 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005086}
5087
Michal Vasko730dfdf2015-08-11 14:48:05 +02005088/**
5089 * @brief Resolve base identity. Logs directly.
5090 *
5091 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02005092 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005093 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01005094 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01005095 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005096 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005097 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005098 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005099static int
Michal Vaskof2d43962016-09-02 11:10:16 +02005100resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02005101 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005102{
5103 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02005104 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01005105 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02005106 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01005107 struct lys_module *mod;
5108
5109 assert((ident && !type) || (!ident && type));
5110
5111 if (!type) {
5112 /* have ident to resolve */
5113 ret = &target;
5114 flags = ident->flags;
5115 mod = ident->module;
5116 } else {
5117 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02005118 ++type->info.ident.count;
5119 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 +02005120 LY_CHECK_ERR_RETURN(!type->info.ident.ref, LOGMEM, -1);
Michal Vaskof2d43962016-09-02 11:10:16 +02005121
5122 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01005123 flags = type->parent->flags;
5124 mod = type->parent->module;
5125 }
Michal Vaskof2006002016-04-21 16:28:15 +02005126 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005127
5128 /* search for the base identity */
5129 name = strchr(basename, ':');
5130 if (name) {
5131 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02005132 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005133 name++;
5134
Michal Vasko2d851a92015-10-20 16:16:36 +02005135 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005136 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02005137 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005138 }
5139 } else {
5140 name = basename;
5141 }
5142
Radek Krejcic071c542016-01-27 14:57:51 +01005143 /* get module where to search */
5144 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
5145 if (!module) {
5146 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01005147 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01005148 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005149 }
5150
Radek Krejcic071c542016-01-27 14:57:51 +01005151 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02005152 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
5153 if (!rc) {
5154 assert(*ret);
5155
5156 /* check status */
5157 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
5158 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
5159 rc = -1;
Radek Krejci83a4bac2017-02-07 15:53:04 +01005160 } else if (ident) {
5161 ident->base[ident->base_size++] = *ret;
Radek Krejci9e6af732017-04-27 14:40:25 +02005162 if (lys_main_module(mod)->implemented) {
5163 /* in case of the implemented identity, maintain backlinks to it
5164 * from the base identities to make it available when resolving
5165 * data with the identity values (not implemented identity is not
5166 * allowed as an identityref value). */
5167 resolve_identity_backlink_update(ident, *ret);
5168 }
Radek Krejci219fa612016-08-15 10:36:51 +02005169 }
5170 } else if (rc == EXIT_FAILURE) {
5171 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005172 if (type) {
5173 --type->info.ident.count;
5174 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005175 }
5176
Radek Krejci219fa612016-08-15 10:36:51 +02005177 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005178}
5179
Radek Krejci9e6af732017-04-27 14:40:25 +02005180/*
5181 * 1 - true (der is derived from base)
5182 * 0 - false (der is not derived from base)
5183 */
5184static int
5185search_base_identity(struct lys_ident *der, struct lys_ident *base)
5186{
5187 int i;
5188
5189 if (der == base) {
5190 return 1;
5191 } else {
5192 for(i = 0; i < der->base_size; i++) {
5193 if (search_base_identity(der->base[i], base) == 1) {
5194 return 1;
5195 }
5196 }
5197 }
5198
5199 return 0;
5200}
5201
Michal Vasko730dfdf2015-08-11 14:48:05 +02005202/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005203 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005204 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005205 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005206 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005207 * @param[in] node Node where the identityref is being resolved
Radek Krejci9e6af732017-04-27 14:40:25 +02005208 * @param[in] dflt flag if we are resolving default value in the schema
Michal Vasko730dfdf2015-08-11 14:48:05 +02005209 *
5210 * @return Pointer to the identity resolvent, NULL on error.
5211 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005212struct lys_ident *
Radek Krejci9e6af732017-04-27 14:40:25 +02005213resolve_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 +02005214{
Radek Krejci9e6af732017-04-27 14:40:25 +02005215 const char *mod_name, *name;
Michal Vasko50576712017-07-28 12:28:33 +02005216 int mod_name_len, nam_len, rc, i, j;
Radek Krejci9e6af732017-04-27 14:40:25 +02005217 int make_implemented = 0;
Radek Krejci85a54be2016-10-20 12:39:56 +02005218 unsigned int u;
Michal Vaskof2d43962016-09-02 11:10:16 +02005219 struct lys_ident *der, *cur;
Radek Krejci9e6af732017-04-27 14:40:25 +02005220 struct lys_module *imod = NULL, *m;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005221
Radek Krejci9e6af732017-04-27 14:40:25 +02005222 assert(type && ident_name && node && mod);
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005223
Michal Vaskof2d43962016-09-02 11:10:16 +02005224 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005225 return NULL;
5226 }
5227
Michal Vasko50576712017-07-28 12:28:33 +02005228 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, &nam_len, NULL, 0);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005229 if (rc < 1) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005230 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005231 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005232 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005233 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005234 return NULL;
5235 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005236
5237 m = lys_main_module(mod); /* shortcut */
5238 if (!mod_name || (!strncmp(mod_name, m->name, mod_name_len) && !m->name[mod_name_len])) {
5239 /* identity is defined in the same module as node */
5240 imod = m;
5241 } else if (dflt) {
5242 /* solving identityref in default definition in schema -
5243 * find the identity's module in the imported modules list to have a correct revision */
5244 for (i = 0; i < mod->imp_size; i++) {
5245 if (!strncmp(mod_name, mod->imp[i].module->name, mod_name_len) && !mod->imp[i].module->name[mod_name_len]) {
5246 imod = mod->imp[i].module;
5247 break;
5248 }
5249 }
5250 } else {
5251 /* solving identityref in data - get the (implemented) module from the context */
5252 u = 0;
5253 while ((imod = (struct lys_module*)ly_ctx_get_module_iter(mod->ctx, &u))) {
5254 if (imod->implemented && !strncmp(mod_name, imod->name, mod_name_len) && !imod->name[mod_name_len]) {
5255 break;
5256 }
5257 }
5258 }
5259 if (!imod) {
5260 goto fail;
5261 }
5262
5263 if (dflt && (m != imod || lys_main_module(type->parent->module) != mod)) {
5264 /* we are solving default statement in schema AND the type is not referencing the same schema,
5265 * THEN, we may need to make the module with the identity implemented, but only if it really
5266 * contains the identity */
5267 if (!imod->implemented) {
5268 cur = NULL;
5269 /* get the identity in the module */
5270 for (i = 0; i < imod->ident_size; i++) {
5271 if (!strcmp(name, imod->ident[i].name)) {
5272 cur = &imod->ident[i];
5273 break;
5274 }
5275 }
5276 if (!cur) {
5277 /* go through includes */
5278 for (j = 0; j < imod->inc_size; j++) {
5279 for (i = 0; i < imod->inc[j].submodule->ident_size; i++) {
5280 if (!strcmp(name, imod->inc[j].submodule->ident[i].name)) {
5281 cur = &imod->inc[j].submodule->ident[i];
5282 break;
5283 }
5284 }
5285 }
5286 if (!cur) {
5287 goto fail;
5288 }
5289 }
5290
5291 /* check that identity is derived from one of the type's base */
5292 while (type->der) {
5293 for (i = 0; i < type->info.ident.count; i++) {
5294 if (search_base_identity(cur, type->info.ident.ref[i])) {
5295 /* cur's base matches the type's base */
5296 make_implemented = 1;
5297 goto match;
5298 }
5299 }
5300 type = &type->der->type;
5301 }
5302 /* matching base not found */
5303 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5304 goto fail;
5305 }
Radek Krejcif32c5f62016-12-05 09:27:38 +01005306 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005307
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005308 /* go through all the derived types of all the bases */
Michal Vaskof2d43962016-09-02 11:10:16 +02005309 while (type->der) {
5310 for (i = 0; i < type->info.ident.count; ++i) {
5311 cur = type->info.ident.ref[i];
Michal Vaskofb0873c2015-08-21 09:00:07 +02005312
Radek Krejci85a54be2016-10-20 12:39:56 +02005313 if (cur->der) {
Radek Krejci98a1e2d2017-04-26 14:34:52 +02005314 /* there are some derived identities */
Radek Krejci85a54be2016-10-20 12:39:56 +02005315 for (u = 0; u < cur->der->number; u++) {
5316 der = (struct lys_ident *)cur->der->set.g[u]; /* shortcut */
Radek Krejci9e6af732017-04-27 14:40:25 +02005317 if (!strcmp(der->name, name) && lys_main_module(der->module) == imod) {
Radek Krejci85a54be2016-10-20 12:39:56 +02005318 /* we have match */
5319 cur = der;
5320 goto match;
5321 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005322 }
5323 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005324 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005325 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005326 }
5327
Radek Krejci9e6af732017-04-27 14:40:25 +02005328fail:
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005329 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005330 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005331
5332match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005333 for (i = 0; i < cur->iffeature_size; i++) {
5334 if (!resolve_iffeature(&cur->iffeature[i])) {
Radek Krejcibb1ce0f2016-12-05 13:24:33 +01005335 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Michal Vasko51e5c582017-01-19 14:16:39 +01005336 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 +02005337 return NULL;
5338 }
5339 }
Radek Krejci9e6af732017-04-27 14:40:25 +02005340 if (make_implemented) {
5341 LOGVRB("Making \"%s\" module implemented because of identityref default value \"%s\" used in the implemented \"%s\" module",
5342 imod->name, cur->name, mod->name);
5343 if (lys_set_implemented(imod)) {
5344 LOGERR(ly_errno, "Setting the module \"%s\" implemented because of used default identity \"%s\" failed.",
5345 imod->name, cur->name);
5346 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity used as identityref value is not implemented.");
5347 goto fail;
5348 }
5349 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005350 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005351}
5352
Michal Vasko730dfdf2015-08-11 14:48:05 +02005353/**
Michal Vaskobb211122015-08-19 14:03:11 +02005354 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005355 *
Michal Vaskobb211122015-08-19 14:03:11 +02005356 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005357 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005358 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005359 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005360 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005361static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005362resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005363{
Radek Krejci93def382017-05-24 15:33:48 +02005364 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005365 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005366
Radek Krejci6ff885d2017-01-03 14:06:22 +01005367 /* 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 +02005368 * in some uses. When we see such a uses, the grouping's unres counter is used to store number of so far
5369 * unresolved uses. The grouping cannot be used unless this counter is decreased back to 0. To remember
5370 * that the uses already increased grouping's counter, the LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005371 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 +02005372
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005373 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005374 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5375 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005376 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005377 return -1;
5378 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005379 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005380 return -1;
5381 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005382 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005383 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5384 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5385 return -1;
5386 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005387 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005388 }
Michal Vasko92981a62016-10-14 10:25:16 +02005389 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005390 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005391 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005392 }
5393
Radek Krejci93def382017-05-24 15:33:48 +02005394 if (uses->grp->unres_count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005395 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005396 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
5397 LOGERR(LY_EINT, "Too many unresolved items (uses) inside a grouping.");
5398 return -1;
5399 }
Radek Krejci010e54b2016-03-15 09:40:34 +01005400 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005401 } else {
5402 /* instantiate grouping only when it is completely resolved */
5403 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005404 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005405 return EXIT_FAILURE;
5406 }
5407
Radek Krejci48464ed2016-03-17 15:44:09 +01005408 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005409 if (!rc) {
5410 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005411 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci93def382017-05-24 15:33:48 +02005412 assert(((struct lys_node_grp *)par_grp)->unres_count);
5413 ((struct lys_node_grp *)par_grp)->unres_count--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005414 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005415 }
Radek Krejcicf509982015-12-15 09:22:44 +01005416
5417 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005418 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005419 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005420 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005421 return -1;
5422 }
5423
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005424 return EXIT_SUCCESS;
5425 }
5426
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005427 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005428}
5429
Michal Vasko730dfdf2015-08-11 14:48:05 +02005430/**
Michal Vasko9957e592015-08-17 15:04:09 +02005431 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005432 *
Michal Vaskobb211122015-08-19 14:03:11 +02005433 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005434 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005435 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005436 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005437 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005438static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005439resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005440{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005441 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005442 const char *value;
Radek Krejcia98048c2017-05-24 16:35:48 +02005443 char *s = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005444
5445 for (i = 0; i < list->keys_size; ++i) {
Radek Krejcidea17dd2017-06-02 15:20:43 +02005446 assert(keys_str);
5447
Radek Krejci5c08a992016-11-02 13:30:04 +01005448 if (!list->child) {
5449 /* no child, possible forward reference */
5450 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5451 return EXIT_FAILURE;
5452 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005453 /* get the key name */
5454 if ((value = strpbrk(keys_str, " \t\n"))) {
5455 len = value - keys_str;
5456 while (isspace(value[0])) {
5457 value++;
5458 }
5459 } else {
5460 len = strlen(keys_str);
5461 }
5462
Radek Krejcia98048c2017-05-24 16:35:48 +02005463 if (list->keys[i]) {
5464 /* skip already resolved keys */
5465 goto next;
5466 }
5467
Michal Vaskobb520442017-05-23 10:55:18 +02005468 rc = lys_getnext_data(lys_node_module((struct lys_node *)list), (struct lys_node *)list, keys_str, len, LYS_LEAF,
5469 (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005470 if (rc) {
Radek Krejcia98048c2017-05-24 16:35:48 +02005471 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list key", keys_str);
Michal Vasko7a55bea2016-05-02 14:51:20 +02005472 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005473 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005474
Radek Krejci48464ed2016-03-17 15:44:09 +01005475 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005476 /* check_key logs */
5477 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005478 }
5479
Radek Krejcicf509982015-12-15 09:22:44 +01005480 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005481 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005482 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5483 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005484 return -1;
5485 }
5486
Radek Krejcia98048c2017-05-24 16:35:48 +02005487 /* default value - is ignored, keep it but print a warning */
5488 if (list->keys[i]->dflt) {
5489 /* log is not hidden only in case this resolving fails and in such a case
5490 * we cannot get here
5491 */
5492 assert(*ly_vlog_hide_location());
5493 ly_vlog_hide(0);
5494 LOGWRN("Default value \"%s\" in the list key \"%s\" is ignored. (%s)", list->keys[i]->dflt,
5495 list->keys[i]->name, s = lys_path((struct lys_node*)list));
5496 ly_vlog_hide(1);
5497 free(s);
5498 }
5499
5500next:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005501 /* prepare for next iteration */
5502 while (value && isspace(value[0])) {
5503 value++;
5504 }
5505 keys_str = value;
5506 }
5507
Michal Vaskof02e3742015-08-05 16:27:02 +02005508 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005509}
5510
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005511/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005512 * @brief Resolve (check) all must conditions of \p node.
5513 * Logs directly.
5514 *
5515 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005516 * @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 +02005517 *
5518 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5519 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005520static int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005521resolve_must(struct lyd_node *node, int inout_parent, int ignore_fail)
Michal Vaskof02e3742015-08-05 16:27:02 +02005522{
Michal Vasko3cfa3182017-01-17 10:00:58 +01005523 int node_flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005524 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005525 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005526 struct lys_restr *must;
5527 struct lyxp_set set;
5528
5529 assert(node);
5530 memset(&set, 0, sizeof set);
5531
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005532 if (inout_parent) {
5533 for (schema = lys_parent(node->schema);
5534 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5535 schema = lys_parent(schema));
5536 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5537 LOGINT;
5538 return -1;
5539 }
5540 must_size = ((struct lys_node_inout *)schema)->must_size;
5541 must = ((struct lys_node_inout *)schema)->must;
5542
Michal Vasko3cfa3182017-01-17 10:00:58 +01005543 node_flags = schema->flags;
5544
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005545 /* context node is the RPC/action */
5546 node = node->parent;
5547 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5548 LOGINT;
5549 return -1;
5550 }
5551 } else {
5552 switch (node->schema->nodetype) {
5553 case LYS_CONTAINER:
5554 must_size = ((struct lys_node_container *)node->schema)->must_size;
5555 must = ((struct lys_node_container *)node->schema)->must;
5556 break;
5557 case LYS_LEAF:
5558 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5559 must = ((struct lys_node_leaf *)node->schema)->must;
5560 break;
5561 case LYS_LEAFLIST:
5562 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5563 must = ((struct lys_node_leaflist *)node->schema)->must;
5564 break;
5565 case LYS_LIST:
5566 must_size = ((struct lys_node_list *)node->schema)->must_size;
5567 must = ((struct lys_node_list *)node->schema)->must;
5568 break;
5569 case LYS_ANYXML:
5570 case LYS_ANYDATA:
5571 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5572 must = ((struct lys_node_anydata *)node->schema)->must;
5573 break;
5574 case LYS_NOTIF:
5575 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5576 must = ((struct lys_node_notif *)node->schema)->must;
5577 break;
5578 default:
5579 must_size = 0;
5580 break;
5581 }
Michal Vasko3cfa3182017-01-17 10:00:58 +01005582
5583 node_flags = node->schema->flags;
Michal Vaskobf19d252015-10-08 15:39:17 +02005584 }
5585
5586 for (i = 0; i < must_size; ++i) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005587 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, lyd_node_module(node), &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005588 return -1;
5589 }
5590
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005591 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005592
Michal Vasko8146d4c2016-05-09 15:50:29 +02005593 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01005594 if ((ignore_fail == 1) || ((node_flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005595 LOGVRB("Must condition \"%s\" not satisfied, but it is not required.", must[i].expr);
5596 } else {
5597 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5598 if (must[i].emsg) {
Michal Vasko51e5c582017-01-19 14:16:39 +01005599 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL, must[i].emsg);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005600 }
5601 if (must[i].eapptag) {
5602 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5603 }
5604 return 1;
Michal Vasko6ac68282016-04-11 10:56:47 +02005605 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005606 }
5607 }
5608
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005609 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005610}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005611
Michal Vaskobf19d252015-10-08 15:39:17 +02005612/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005613 * @brief Resolve (find) when condition schema context node. Does not log.
5614 *
5615 * @param[in] schema Schema node with the when condition.
5616 * @param[out] ctx_snode When schema context node.
5617 * @param[out] ctx_snode_type Schema context node type.
5618 */
5619void
5620resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5621{
5622 const struct lys_node *sparent;
5623
5624 /* find a not schema-only node */
5625 *ctx_snode_type = LYXP_NODE_ELEM;
5626 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5627 if (schema->nodetype == LYS_AUGMENT) {
5628 sparent = ((struct lys_node_augment *)schema)->target;
5629 } else {
5630 sparent = schema->parent;
5631 }
5632 if (!sparent) {
5633 /* context node is the document root (fake root in our case) */
5634 if (schema->flags & LYS_CONFIG_W) {
5635 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5636 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005637 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005638 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005639 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005640 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005641 break;
5642 }
5643 schema = sparent;
5644 }
5645
5646 *ctx_snode = (struct lys_node *)schema;
5647}
5648
5649/**
Michal Vaskocf024702015-10-08 15:01:42 +02005650 * @brief Resolve (find) when condition context node. Does not log.
5651 *
5652 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005653 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005654 * @param[out] ctx_node Context node.
5655 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005656 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005657 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005658 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005659static int
5660resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5661 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005662{
Michal Vaskocf024702015-10-08 15:01:42 +02005663 struct lyd_node *parent;
5664 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005665 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005666 uint16_t i, data_depth, schema_depth;
5667
Michal Vasko508a50d2016-09-07 14:50:33 +02005668 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005669
Michal Vaskofe989752016-09-08 08:47:26 +02005670 if (node_type == LYXP_NODE_ELEM) {
5671 /* standard element context node */
5672 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5673 for (sparent = schema, schema_depth = 0;
5674 sparent;
5675 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5676 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5677 ++schema_depth;
5678 }
Michal Vaskocf024702015-10-08 15:01:42 +02005679 }
Michal Vaskofe989752016-09-08 08:47:26 +02005680 if (data_depth < schema_depth) {
5681 return -1;
5682 }
Michal Vaskocf024702015-10-08 15:01:42 +02005683
Michal Vasko956e8542016-08-26 09:43:35 +02005684 /* find the corresponding data node */
5685 for (i = 0; i < data_depth - schema_depth; ++i) {
5686 node = node->parent;
5687 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005688 if (node->schema != schema) {
5689 return -1;
5690 }
Michal Vaskofe989752016-09-08 08:47:26 +02005691 } else {
5692 /* root context node */
5693 while (node->parent) {
5694 node = node->parent;
5695 }
5696 while (node->prev->next) {
5697 node = node->prev;
5698 }
Michal Vaskocf024702015-10-08 15:01:42 +02005699 }
5700
Michal Vaskoa59495d2016-08-22 09:18:58 +02005701 *ctx_node = node;
5702 *ctx_node_type = node_type;
5703 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005704}
5705
Michal Vasko76c3bd32016-08-24 16:02:52 +02005706/**
5707 * @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 +01005708 * The context node is adjusted if needed.
Michal Vasko76c3bd32016-08-24 16:02:52 +02005709 *
5710 * @param[in] snode Schema node, whose children instances need to be unlinked.
5711 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5712 * it is moved to point to another sibling still in the original tree.
5713 * @param[in,out] ctx_node When context node, adjusted if needed.
5714 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5715 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5716 * Ordering may change, but there will be no semantic change.
5717 *
5718 * @return EXIT_SUCCESS on success, -1 on error.
5719 */
5720static int
5721resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5722 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5723{
5724 struct lyd_node *next, *elem;
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005725 const struct lys_node *slast;
Michal Vasko76c3bd32016-08-24 16:02:52 +02005726
5727 switch (snode->nodetype) {
5728 case LYS_AUGMENT:
5729 case LYS_USES:
5730 case LYS_CHOICE:
5731 case LYS_CASE:
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005732 slast = NULL;
Michal Vasko24476fa2017-03-08 12:33:48 +01005733 while ((slast = lys_getnext(slast, snode, NULL, LYS_GETNEXT_PARENTUSES))) {
Michal Vaskoeb81fb72017-02-06 12:11:08 +01005734 if (slast->nodetype & (LYS_ACTION | LYS_NOTIF)) {
5735 continue;
5736 }
5737
5738 if (resolve_when_unlink_nodes((struct lys_node *)slast, node, ctx_node, ctx_node_type, unlinked_nodes)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005739 return -1;
5740 }
5741 }
5742 break;
5743 case LYS_CONTAINER:
5744 case LYS_LIST:
5745 case LYS_LEAF:
5746 case LYS_LEAFLIST:
5747 case LYS_ANYXML:
5748 case LYS_ANYDATA:
5749 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5750 if (elem->schema == snode) {
5751
5752 if (elem == *ctx_node) {
5753 /* We are going to unlink our context node! This normally cannot happen,
5754 * but we use normal top-level data nodes for faking a document root node,
5755 * so if this is the context node, we just use the next top-level node.
5756 * Additionally, it can even happen that there are no top-level data nodes left,
5757 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5758 * lyxp_eval() can handle this special situation.
5759 */
5760 if (ctx_node_type == LYXP_NODE_ELEM) {
5761 LOGINT;
5762 return -1;
5763 }
5764
5765 if (elem->prev == elem) {
5766 /* unlinking last top-level element, use an empty data tree */
5767 *ctx_node = NULL;
5768 } else {
5769 /* in this case just use the previous/last top-level data node */
5770 *ctx_node = elem->prev;
5771 }
5772 } else if (elem == *node) {
5773 /* We are going to unlink the currently processed node. This does not matter that
5774 * much, but we would lose access to the original data tree, so just move our
5775 * pointer somewhere still inside it.
5776 */
5777 if ((*node)->prev != *node) {
5778 *node = (*node)->prev;
5779 } else {
5780 /* the processed node with sibings were all unlinked, oh well */
5781 *node = NULL;
5782 }
5783 }
5784
5785 /* temporarily unlink the node */
Michal Vasko2bce30c2017-02-06 12:16:39 +01005786 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005787 if (*unlinked_nodes) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005788 if (lyd_insert_after((*unlinked_nodes)->prev, elem)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005789 LOGINT;
5790 return -1;
5791 }
5792 } else {
5793 *unlinked_nodes = elem;
5794 }
5795
5796 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5797 /* there can be only one instance */
5798 break;
5799 }
5800 }
5801 }
5802 break;
5803 default:
5804 LOGINT;
5805 return -1;
5806 }
5807
5808 return EXIT_SUCCESS;
5809}
5810
5811/**
5812 * @brief Relink the unlinked nodes back.
5813 *
5814 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5815 * we simply need a sibling from the original data tree.
5816 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5817 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5818 * or the sibling of \p unlinked_nodes.
5819 *
5820 * @return EXIT_SUCCESS on success, -1 on error.
5821 */
5822static int
5823resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5824{
5825 struct lyd_node *elem;
5826
5827 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005828 lyd_unlink_internal(elem, 0);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005829 if (ctx_node_type == LYXP_NODE_ELEM) {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005830 if (lyd_insert_common(node, NULL, elem, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005831 return -1;
5832 }
5833 } else {
Michal Vasko2bce30c2017-02-06 12:16:39 +01005834 if (lyd_insert_nextto(node, elem, 0, 0)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005835 return -1;
5836 }
5837 }
5838 }
5839
5840 return EXIT_SUCCESS;
5841}
5842
Radek Krejci03b71f72016-03-16 11:10:09 +01005843int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005844resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005845{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005846 int ret = 0;
5847 uint8_t must_size;
5848 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005849
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005850 assert(node);
5851
5852 schema = node->schema;
5853
5854 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005855 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005856 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005857 must_size = ((struct lys_node_container *)schema)->must_size;
5858 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005859 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005860 must_size = ((struct lys_node_leaf *)schema)->must_size;
5861 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005862 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005863 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5864 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005865 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005866 must_size = ((struct lys_node_list *)schema)->must_size;
5867 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005868 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005869 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005870 must_size = ((struct lys_node_anydata *)schema)->must_size;
5871 break;
5872 case LYS_NOTIF:
5873 must_size = ((struct lys_node_notif *)schema)->must_size;
5874 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005875 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005876 must_size = 0;
5877 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005878 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005879
5880 if (must_size) {
5881 ++ret;
5882 }
5883
5884 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5885 if (!node->prev->next) {
5886 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5887 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5888 ret += 0x2;
5889 }
5890 }
5891
5892 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005893}
5894
5895int
Radek Krejci46165822016-08-26 14:06:27 +02005896resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005897{
Radek Krejci46165822016-08-26 14:06:27 +02005898 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005899
Radek Krejci46165822016-08-26 14:06:27 +02005900 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005901
Radek Krejci46165822016-08-26 14:06:27 +02005902 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005903 return 1;
5904 }
5905
Radek Krejci46165822016-08-26 14:06:27 +02005906 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005907 goto check_augment;
5908
Radek Krejci46165822016-08-26 14:06:27 +02005909 while (parent) {
5910 /* stop conditions */
5911 if (!mode) {
5912 /* stop on node that can be instantiated in data tree */
5913 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5914 break;
5915 }
5916 } else {
5917 /* stop on the specified node */
5918 if (parent == stop) {
5919 break;
5920 }
5921 }
5922
5923 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005924 return 1;
5925 }
5926check_augment:
5927
5928 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005929 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005930 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005931 }
5932 parent = lys_parent(parent);
5933 }
5934
5935 return 0;
5936}
5937
Michal Vaskocf024702015-10-08 15:01:42 +02005938/**
5939 * @brief Resolve (check) all when conditions relevant for \p node.
5940 * Logs directly.
5941 *
5942 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005943 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005944 * @return
5945 * -1 - error, ly_errno is set
5946 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005947 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005948 * 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 +02005949 */
Radek Krejci46165822016-08-26 14:06:27 +02005950int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005951resolve_when(struct lyd_node *node, int *result, int ignore_fail)
Michal Vaskocf024702015-10-08 15:01:42 +02005952{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005953 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005954 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005955 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005956 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005957 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005958
5959 assert(node);
5960 memset(&set, 0, sizeof set);
5961
Michal Vasko78d97e22017-02-21 09:54:38 +01005962 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005963 /* make the node dummy for the evaluation */
5964 node->validity |= LYD_VAL_INUSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005965 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, lyd_node_module(node),
5966 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005967 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005968 if (rc) {
5969 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005970 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005971 }
Radek Krejci51093642016-03-29 10:14:59 +02005972 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005973 }
5974
Radek Krejci03b71f72016-03-16 11:10:09 +01005975 /* set boolean result of the condition */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005976 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, lyd_node_module(node), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005977 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01005978 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01005979 if ((ignore_fail == 1) || ((node->schema->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005980 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
5981 ((struct lys_node_container *)node->schema)->when->cond);
5982 } else {
5983 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
5984 goto cleanup;
5985 }
Michal Vaskocf024702015-10-08 15:01:42 +02005986 }
Radek Krejci51093642016-03-29 10:14:59 +02005987
5988 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01005989 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, lyd_node_module(node), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005990 }
5991
Michal Vasko90fc2a32016-08-24 15:58:58 +02005992 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005993 goto check_augment;
5994
5995 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005996 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5997 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005998 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005999 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006000 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006001 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006002 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006003 }
6004 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006005
6006 unlinked_nodes = NULL;
6007 /* we do not want our node pointer to change */
6008 tmp_node = node;
6009 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6010 if (rc) {
6011 goto cleanup;
6012 }
6013
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006014 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, lys_node_module(sparent),
6015 &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006016
6017 if (unlinked_nodes && ctx_node) {
6018 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6019 rc = -1;
6020 goto cleanup;
6021 }
6022 }
6023
Radek Krejci03b71f72016-03-16 11:10:09 +01006024 if (rc) {
6025 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006026 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006027 }
Radek Krejci51093642016-03-29 10:14:59 +02006028 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006029 }
6030
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006031 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006032 if (!set.val.bool) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01006033 if ((ignore_fail == 1) || ((sparent->flags & LYS_XPATH_DEP) || (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006034 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
6035 ((struct lys_node_uses *)sparent)->when->cond);
6036 } else {
Michal Vasko2cb18e72017-03-28 14:46:33 +02006037 node->when_status |= LYD_WHEN_FALSE;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006038 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
6039 goto cleanup;
6040 }
Michal Vaskocf024702015-10-08 15:01:42 +02006041 }
Radek Krejci51093642016-03-29 10:14:59 +02006042
6043 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006044 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006045 }
6046
6047check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02006048 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006049 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006050 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02006051 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02006052 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02006053 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006054 }
6055 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02006056
6057 unlinked_nodes = NULL;
6058 tmp_node = node;
6059 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
6060 if (rc) {
6061 goto cleanup;
6062 }
6063
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006064 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type,
6065 lys_node_module(sparent->parent), &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02006066
6067 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
6068 * so the tree did not actually change and there is nothing for us to do
6069 */
6070 if (unlinked_nodes && ctx_node) {
6071 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
6072 rc = -1;
6073 goto cleanup;
6074 }
6075 }
6076
Radek Krejci03b71f72016-03-16 11:10:09 +01006077 if (rc) {
6078 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02006079 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01006080 }
Radek Krejci51093642016-03-29 10:14:59 +02006081 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02006082 }
6083
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006084 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, lys_node_module(sparent->parent), LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02006085 if (!set.val.bool) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006086 node->when_status |= LYD_WHEN_FALSE;
Michal Vasko3cfa3182017-01-17 10:00:58 +01006087 if ((ignore_fail == 1) || ((sparent->parent->flags & LYS_XPATH_DEP) && (ignore_fail == 2))) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006088 LOGVRB("When condition \"%s\" is not satisfied, but it is not required.",
Michal Vasko3cfa3182017-01-17 10:00:58 +01006089 ((struct lys_node_augment *)sparent->parent)->when->cond);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006090 } else {
6091 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
6092 goto cleanup;
6093 }
Michal Vaskocf024702015-10-08 15:01:42 +02006094 }
Radek Krejci51093642016-03-29 10:14:59 +02006095
6096 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006097 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, lys_node_module(sparent->parent), 0);
Michal Vaskocf024702015-10-08 15:01:42 +02006098 }
6099
Michal Vasko90fc2a32016-08-24 15:58:58 +02006100 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02006101 }
6102
Radek Krejci0b7704f2016-03-18 12:16:14 +01006103 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01006104
Radek Krejci51093642016-03-29 10:14:59 +02006105cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02006106 /* free xpath set content */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01006107 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, NULL, 0);
Radek Krejci51093642016-03-29 10:14:59 +02006108
Radek Krejci46165822016-08-26 14:06:27 +02006109 if (result) {
6110 if (node->when_status & LYD_WHEN_TRUE) {
6111 *result = 1;
6112 } else {
6113 *result = 0;
6114 }
6115 }
6116
Radek Krejci51093642016-03-29 10:14:59 +02006117 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006118}
6119
Radek Krejcicbb473e2016-09-16 14:48:32 +02006120static int
6121check_leafref_features(struct lys_type *type)
6122{
6123 struct lys_node *iter;
6124 struct ly_set *src_parents, *trg_parents, *features;
6125 unsigned int i, j, size, x;
6126 int ret = EXIT_SUCCESS;
6127
6128 assert(type->parent);
6129
6130 src_parents = ly_set_new();
6131 trg_parents = ly_set_new();
6132 features = ly_set_new();
6133
6134 /* get parents chain of source (leafref) */
Radek Krejciecda01a2017-04-05 15:44:27 +02006135 for (iter = (struct lys_node *)type->parent; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006136 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6137 continue;
6138 }
6139 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
6140 }
6141 /* get parents chain of target */
Radek Krejciecda01a2017-04-05 15:44:27 +02006142 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = lys_parent(iter)) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006143 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
6144 continue;
6145 }
6146 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
6147 }
6148
6149 /* compare the features used in if-feature statements in the rest of both
6150 * chains of parents. The set of features used for target must be a subset
6151 * of features used for the leafref. This is not a perfect, we should compare
6152 * the truth tables but it could require too much resources, so we simplify that */
6153 for (i = 0; i < src_parents->number; i++) {
6154 iter = src_parents->set.s[i]; /* shortcut */
6155 if (!iter->iffeature_size) {
6156 continue;
6157 }
6158 for (j = 0; j < iter->iffeature_size; j++) {
6159 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6160 for (; size; size--) {
6161 if (!iter->iffeature[j].features[size - 1]) {
6162 /* not yet resolved feature, postpone this check */
6163 ret = EXIT_FAILURE;
6164 goto cleanup;
6165 }
6166 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
6167 }
6168 }
6169 }
6170 x = features->number;
6171 for (i = 0; i < trg_parents->number; i++) {
6172 iter = trg_parents->set.s[i]; /* shortcut */
6173 if (!iter->iffeature_size) {
6174 continue;
6175 }
6176 for (j = 0; j < iter->iffeature_size; j++) {
6177 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
6178 for (; size; size--) {
6179 if (!iter->iffeature[j].features[size - 1]) {
6180 /* not yet resolved feature, postpone this check */
6181 ret = EXIT_FAILURE;
6182 goto cleanup;
6183 }
6184 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
6185 /* the feature is not present in features set of target's parents chain */
6186 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
Michal Vasko51e5c582017-01-19 14:16:39 +01006187 LOGVAL(LYE_SPEC, LY_VLOG_PREV, NULL,
Radek Krejcicbb473e2016-09-16 14:48:32 +02006188 "Leafref is not conditional based on \"%s\" feature as its target.",
6189 iter->iffeature[j].features[size - 1]->name);
6190 ret = -1;
6191 goto cleanup;
6192 }
6193 }
6194 }
6195 }
6196
6197cleanup:
6198 ly_set_free(features);
6199 ly_set_free(src_parents);
6200 ly_set_free(trg_parents);
6201
6202 return ret;
6203}
6204
Michal Vaskoc5c55ca2017-06-30 13:15:18 +02006205static int
6206check_type_union_leafref(struct lys_type *type)
6207{
6208 uint8_t i;
6209
6210 if ((type->base == LY_TYPE_UNION) && type->info.uni.count) {
6211 /* go through unions and look for leafref */
6212 for (i = 0; i < type->info.uni.count; ++i) {
6213 switch (type->info.uni.types[i].base) {
6214 case LY_TYPE_LEAFREF:
6215 return 1;
6216 case LY_TYPE_UNION:
6217 if (check_type_union_leafref(&type->info.uni.types[i])) {
6218 return 1;
6219 }
6220 break;
6221 default:
6222 break;
6223 }
6224 }
6225
6226 return 0;
6227 }
6228
6229 /* just inherit the flag value */
6230 return type->der->has_union_leafref;
6231}
6232
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006233/**
Michal Vaskobb211122015-08-19 14:03:11 +02006234 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006235 *
6236 * @param[in] mod Main module.
6237 * @param[in] item Item to resolve. Type determined by \p type.
6238 * @param[in] type Type of the unresolved item.
6239 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02006240 * @param[in] unres Unres schema structure to use.
Michal Vasko769f8032017-01-24 13:11:55 +01006241 * @param[in] final_fail Whether we are just printing errors of the failed unres items.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006242 *
6243 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6244 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006245static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006246resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Michal Vasko769f8032017-01-24 13:11:55 +01006247 struct unres_schema *unres, int final_fail)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006248{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006249 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006250 int rc = -1, has_str = 0, parent_type = 0, i, k;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006251 unsigned int j;
Radek Krejci80056d52017-01-05 13:13:33 +01006252 struct lys_node *root, *next, *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006253 const char *expr;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006254 uint8_t *u;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006255
Radek Krejcic79c6b12016-07-26 15:11:49 +02006256 struct ly_set *refs, *procs;
6257 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006258 struct lys_ident *ident;
6259 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006260 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01006261 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006262 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006263 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006264 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006265 struct unres_ext *ext_data;
Radek Krejci80056d52017-01-05 13:13:33 +01006266 struct lys_ext_instance *ext, **extlist;
6267 struct lyext_plugin *eplugin;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006268
6269 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006270 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006271 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006272 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006273 ident = item;
6274
Radek Krejci018f1f52016-08-03 16:01:20 +02006275 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006276 break;
6277 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006278 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006279 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006280 stype = item;
6281
Radek Krejci018f1f52016-08-03 16:01:20 +02006282 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006283 break;
6284 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02006285 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006286 stype = item;
6287
Michal Vasko1c007172017-03-10 10:20:44 +01006288 rc = resolve_schema_leafref(stype->info.lref.path, node, (const struct lys_node **)&stype->info.lref.target);
6289 if (!rc) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02006290 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02006291 /* check if leafref and its target are under a common if-features */
6292 rc = check_leafref_features(stype);
6293 if (rc) {
6294 break;
6295 }
6296
Michal Vaskobb520442017-05-23 10:55:18 +02006297 if (lys_node_module(node)->implemented) {
6298 /* make all the modules on the path implemented */
6299 for (next = (struct lys_node *)stype->info.lref.target; next; next = lys_parent(next)) {
6300 if (!lys_node_module(next)->implemented) {
6301 if (lys_set_implemented(lys_node_module(next))) {
6302 rc = -1;
6303 break;
6304 }
6305 }
6306 }
6307 if (next) {
6308 break;
6309 }
6310
6311 /* store the backlink from leafref target */
6312 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
6313 rc = -1;
6314 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006315 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01006316 }
6317
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006318 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006319 case UNRES_TYPE_DER_EXT:
6320 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006321 /* falls through */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006322 case UNRES_TYPE_DER_TPDF:
Radek Krejci8d6b7422017-02-03 14:42:13 +01006323 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006324 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006325 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01006326 /* parent */
6327 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006328 stype = item;
6329
Michal Vasko88c29542015-11-27 14:57:53 +01006330 /* HACK type->der is temporarily unparsed type statement */
6331 yin = (struct lyxml_elem *)stype->der;
6332 stype->der = NULL;
6333
Pavol Vicana0e4e672016-02-24 12:20:04 +01006334 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6335 yang = (struct yang_type *)yin;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006336 rc = yang_check_type(mod, node, yang, stype, parent_type, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006337
6338 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02006339 /* may try again later */
6340 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006341 } else {
6342 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02006343 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01006344 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01006345 }
6346
Michal Vasko88c29542015-11-27 14:57:53 +01006347 } else {
Radek Krejci8d6b7422017-02-03 14:42:13 +01006348 rc = fill_yin_type(mod, node, yin, stype, parent_type, unres);
Radek Krejci63fc0962017-02-15 13:20:18 +01006349 if (!rc || rc == -1) {
Pavol Vicana0e4e672016-02-24 12:20:04 +01006350 /* we need to always be able to free this, it's safe only in this case */
6351 lyxml_free(mod->ctx, yin);
6352 } else {
6353 /* may try again later, put all back how it was */
6354 stype->der = (struct lys_tpdf *)yin;
6355 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006356 }
Radek Krejcic13db382016-08-16 10:52:42 +02006357 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006358 /* it does not make sense to have leaf-list of empty type */
Radek Krejci8d6b7422017-02-03 14:42:13 +01006359 if (!parent_type && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02006360 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
6361 }
Michal Vaskoc5c55ca2017-06-30 13:15:18 +02006362
6363 if ((type == UNRES_TYPE_DER_TPDF) && (stype->base == LY_TYPE_UNION)) {
6364 /* fill typedef union leafref flag */
6365 ((struct lys_tpdf *)stype->parent)->has_union_leafref = check_type_union_leafref(stype);
6366 } else if ((type == UNRES_TYPE_DER) && stype->der->has_union_leafref) {
6367 /* copy the type in case it has union leafref flag */
6368 if (lys_copy_union_leafrefs(mod, node, stype, NULL, unres)) {
6369 LOGERR(LY_EINT, "Failed to duplicate type.");
6370 return -1;
6371 }
6372 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006373 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02006374 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
6375 * 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 +02006376 * grouping. The grouping cannot be used unless the unres counter is 0.
6377 * To remember that the grouping already increased the counter, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02006378 * of the type's base member. */
6379 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
6380 if (par_grp) {
Radek Krejci93def382017-05-24 15:33:48 +02006381 if (++((struct lys_node_grp *)par_grp)->unres_count == 0) {
6382 LOGERR(LY_EINT, "Too many unresolved items (type) inside a grouping.");
6383 return -1;
6384 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02006385 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006386 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006387 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006388 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006389 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006390 iff_data = str_snode;
6391 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006392 if (!rc) {
6393 /* success */
Radek Krejci9de2c042016-10-19 16:53:06 +02006394 if (iff_data->infeature) {
6395 /* store backlink into the target feature to allow reverse changes in case of changing feature status */
6396 feat = *((struct lys_feature **)item);
6397 if (!feat->depfeatures) {
6398 feat->depfeatures = ly_set_new();
6399 }
Radek Krejci85a54be2016-10-20 12:39:56 +02006400 ly_set_add(feat->depfeatures, iff_data->node, LY_SET_OPT_USEASLIST);
Radek Krejci9de2c042016-10-19 16:53:06 +02006401 }
6402 /* cleanup temporary data */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006403 lydict_remove(mod->ctx, iff_data->fname);
6404 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006405 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006406 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006407 case UNRES_FEATURE:
6408 feat = (struct lys_feature *)item;
6409
6410 if (feat->iffeature_size) {
6411 refs = ly_set_new();
6412 procs = ly_set_new();
6413 ly_set_add(procs, feat, 0);
6414
6415 while (procs->number) {
6416 ref = procs->set.g[procs->number - 1];
6417 ly_set_rm_index(procs, procs->number - 1);
6418
6419 for (i = 0; i < ref->iffeature_size; i++) {
6420 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6421 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006422 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006423 if (ref->iffeature[i].features[j - 1] == feat) {
6424 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6425 goto featurecheckdone;
6426 }
6427
6428 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6429 k = refs->number;
6430 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6431 /* not yet seen feature, add it for processing */
6432 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6433 }
6434 }
6435 } else {
6436 /* forward reference */
6437 rc = EXIT_FAILURE;
6438 goto featurecheckdone;
6439 }
6440 }
6441
6442 }
6443 }
6444 rc = EXIT_SUCCESS;
6445
6446featurecheckdone:
6447 ly_set_free(refs);
6448 ly_set_free(procs);
6449 }
6450
6451 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006452 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006453 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006455 case UNRES_TYPEDEF_DFLT:
6456 parent_type++;
Radek Krejci3d679d72017-08-01 10:44:37 +02006457 /* falls through */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006458 case UNRES_TYPE_DFLT:
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006459 stype = item;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006460 rc = check_default(stype, (const char **)str_snode, mod, parent_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006461 break;
6462 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006463 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006464 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006465 choic = item;
6466
Radek Krejcie00d2312016-08-12 15:27:49 +02006467 if (!choic->dflt) {
6468 choic->dflt = resolve_choice_dflt(choic, expr);
6469 }
Michal Vasko7955b362015-09-04 14:18:15 +02006470 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006471 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006472 } else {
6473 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006474 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006475 break;
6476 case UNRES_LIST_KEYS:
Radek Krejci5c08a992016-11-02 13:30:04 +01006477 rc = resolve_list_keys(item, ((struct lys_node_list *)item)->keys_str);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006478 break;
6479 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006480 unique_info = (struct unres_list_uniq *)item;
6481 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006482 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006483 case UNRES_AUGMENT:
Radek Krejcib3142312016-11-09 11:04:12 +01006484 rc = resolve_augment(item, NULL, unres);
Michal Vasko7178e692016-02-12 15:58:05 +01006485 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006486 case UNRES_XPATH:
6487 node = (struct lys_node *)item;
Michal Vasko769f8032017-01-24 13:11:55 +01006488 rc = lys_check_xpath(node, 1, final_fail);
Michal Vasko508a50d2016-09-07 14:50:33 +02006489 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006490 case UNRES_EXT:
6491 ext_data = (struct unres_ext *)str_snode;
Radek Krejci2b999ac2017-01-18 16:22:12 +01006492 extlist = &(*(struct lys_ext_instance ***)item)[ext_data->ext_index];
Radek Krejcia7db9702017-01-20 12:55:14 +01006493 rc = resolve_extension(ext_data, extlist, unres);
Radek Krejcie534c132016-11-23 13:32:31 +01006494 if (!rc) {
Radek Krejci79685c92017-02-17 10:49:43 +01006495 /* success */
Radek Krejci80056d52017-01-05 13:13:33 +01006496 /* is there a callback to be done to finalize the extension? */
Radek Krejci2b999ac2017-01-18 16:22:12 +01006497 eplugin = extlist[0]->def->plugin;
Radek Krejci80056d52017-01-05 13:13:33 +01006498 if (eplugin) {
6499 if (eplugin->check_result || (eplugin->flags & LYEXT_OPT_INHERIT)) {
Radek Krejci2b999ac2017-01-18 16:22:12 +01006500 u = malloc(sizeof *u);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006501 LY_CHECK_ERR_RETURN(!u, LOGMEM, -1);
Radek Krejci2b999ac2017-01-18 16:22:12 +01006502 (*u) = ext_data->ext_index;
Radek Krejcib08bc172017-02-27 13:17:14 +01006503 if (unres_schema_add_node(mod, unres, item, UNRES_EXT_FINALIZE, (struct lys_node *)u) == -1) {
6504 /* something really bad happend since the extension finalization is not actually
6505 * being resolved while adding into unres, so something more serious with the unres
6506 * list itself must happened */
6507 return -1;
6508 }
Radek Krejci80056d52017-01-05 13:13:33 +01006509 }
6510 }
Radek Krejci79685c92017-02-17 10:49:43 +01006511 }
6512 if (!rc || rc == -1) {
6513 /* cleanup on success or fatal error */
6514 if (ext_data->datatype == LYS_IN_YIN) {
6515 /* YIN */
6516 lyxml_free(mod->ctx, ext_data->data.yin);
6517 } else {
PavolVicandb0e8172017-02-20 00:46:09 +01006518 /* YANG */
6519 yang_free_ext_data(ext_data->data.yang);
Radek Krejci79685c92017-02-17 10:49:43 +01006520 }
Radek Krejci2b999ac2017-01-18 16:22:12 +01006521 free(ext_data);
Radek Krejcie534c132016-11-23 13:32:31 +01006522 }
6523 break;
Radek Krejci80056d52017-01-05 13:13:33 +01006524 case UNRES_EXT_FINALIZE:
Radek Krejci2b999ac2017-01-18 16:22:12 +01006525 u = (uint8_t *)str_snode;
6526 ext = (*(struct lys_ext_instance ***)item)[*u];
6527 free(u);
6528
Radek Krejci80056d52017-01-05 13:13:33 +01006529 eplugin = ext->def->plugin;
6530
6531 /* inherit */
6532 if ((eplugin->flags & LYEXT_OPT_INHERIT) && (ext->parent_type == LYEXT_PAR_NODE)) {
6533 root = (struct lys_node *)ext->parent;
6534 if (!(root->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
6535 LY_TREE_DFS_BEGIN(root->child, next, node) {
6536 /* first, check if the node already contain instance of the same extension,
6537 * in such a case we won't inherit. In case the node was actually defined as
6538 * augment data, we are supposed to check the same way also the augment node itself */
6539 if (lys_ext_instance_presence(ext->def, node->ext, node->ext_size) != -1) {
6540 goto inherit_dfs_sibling;
6541 } else if (node->parent != root && node->parent->nodetype == LYS_AUGMENT &&
6542 lys_ext_instance_presence(ext->def, node->parent->ext, node->parent->ext_size) != -1) {
6543 goto inherit_dfs_sibling;
6544 }
6545
6546 if (eplugin->check_inherit) {
6547 /* we have a callback to check the inheritance, use it */
6548 switch ((rc = (*eplugin->check_inherit)(ext, node))) {
6549 case 0:
6550 /* yes - continue with the inheriting code */
6551 break;
6552 case 1:
6553 /* no - continue with the node's sibling */
6554 goto inherit_dfs_sibling;
6555 case 2:
6556 /* no, but continue with the children, just skip the inheriting code for this node */
6557 goto inherit_dfs_child;
6558 default:
6559 LOGERR(LY_EINT, "Plugin's (%s:%s) check_inherit callback returns invalid value (%d),",
6560 ext->def->module->name, ext->def->name, rc);
6561 }
6562 }
6563
6564 /* inherit the extension */
6565 extlist = realloc(node->ext, (node->ext_size + 1) * sizeof *node->ext);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006566 LY_CHECK_ERR_RETURN(!extlist, LOGMEM, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006567 extlist[node->ext_size] = malloc(sizeof **extlist);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006568 LY_CHECK_ERR_RETURN(!extlist[node->ext_size], LOGMEM; node->ext = extlist, -1);
Radek Krejci80056d52017-01-05 13:13:33 +01006569 memcpy(extlist[node->ext_size], ext, sizeof *ext);
6570 extlist[node->ext_size]->flags |= LYEXT_OPT_INHERIT;
6571
6572 node->ext = extlist;
6573 node->ext_size++;
6574
6575inherit_dfs_child:
6576 /* modification of - select element for the next run - children first */
6577 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
6578 next = NULL;
6579 } else {
6580 next = node->child;
6581 }
6582 if (!next) {
6583inherit_dfs_sibling:
6584 /* no children, try siblings */
6585 next = node->next;
6586 }
6587 while (!next) {
6588 /* go to the parent */
6589 node = lys_parent(node);
6590
6591 /* we are done if we are back in the root (the starter's parent */
6592 if (node == root) {
6593 break;
6594 }
6595
6596 /* parent is already processed, go to its sibling */
6597 next = node->next;
6598 }
6599 }
6600 }
6601 }
6602
6603 /* final check */
6604 if (eplugin->check_result) {
6605 if ((*eplugin->check_result)(ext)) {
Radek Krejci2c121b32017-02-24 10:03:16 +01006606 ly_errno = LY_EEXT;
Radek Krejci80056d52017-01-05 13:13:33 +01006607 return -1;
6608 }
6609 }
6610
6611 rc = 0;
6612 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006613 default:
6614 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006615 break;
6616 }
6617
Radek Krejci54081ce2016-08-12 15:21:47 +02006618 if (has_str && !rc) {
6619 /* the string is no more needed in case of success.
6620 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006621 lydict_remove(mod->ctx, str_snode);
6622 }
6623
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006624 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006625}
6626
Michal Vaskof02e3742015-08-05 16:27:02 +02006627/* logs directly */
6628static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006629print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006630{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006631 struct lyxml_elem *xml;
6632 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006633 struct unres_iffeat_data *iff_data;
Radek Krejcie534c132016-11-23 13:32:31 +01006634 const char *name = NULL;
6635 struct unres_ext *extinfo;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006636
Michal Vaskof02e3742015-08-05 16:27:02 +02006637 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006638 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006639 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006640 break;
6641 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006642 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006643 break;
6644 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006645 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6646 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006647 break;
Radek Krejci8d6b7422017-02-03 14:42:13 +01006648 case UNRES_TYPE_DER_EXT:
Radek Krejci3a5501d2016-07-18 22:03:34 +02006649 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006650 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006651 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6652 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
Radek Krejcie534c132016-11-23 13:32:31 +01006653 name = ((struct yang_type *)xml)->name;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006654 } else {
6655 LY_TREE_FOR(xml->attr, attr) {
6656 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
Radek Krejcie534c132016-11-23 13:32:31 +01006657 name = attr->value;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006658 break;
6659 }
6660 }
6661 assert(attr);
6662 }
Radek Krejcie534c132016-11-23 13:32:31 +01006663 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006664 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006665 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006666 iff_data = str_node;
6667 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006668 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006669 case UNRES_FEATURE:
6670 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6671 ((struct lys_feature *)item)->name);
6672 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006673 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006674 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006675 break;
Radek Krejciab08f0f2017-03-09 16:37:15 +01006676 case UNRES_TYPEDEF_DFLT:
Michal Vaskof02e3742015-08-05 16:27:02 +02006677 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006678 if (str_node) {
6679 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6680 } /* else no default value in the type itself, but we are checking some restrictions against
6681 * possible default value of some base type. The failure is caused by not resolved base type,
6682 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006683 break;
6684 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006685 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006686 break;
6687 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006688 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006689 break;
6690 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006691 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006692 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006693 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006694 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6695 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006696 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006697 case UNRES_XPATH:
Michal Vasko0d198372016-11-16 11:40:03 +01006698 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "XPath expressions of",
6699 ((struct lys_node *)item)->name);
Michal Vasko508a50d2016-09-07 14:50:33 +02006700 break;
Radek Krejcie534c132016-11-23 13:32:31 +01006701 case UNRES_EXT:
6702 extinfo = (struct unres_ext *)str_node;
6703 name = extinfo->datatype == LYS_IN_YIN ? extinfo->data.yin->name : NULL; /* TODO YANG extension */
6704 LOGVRB("Resolving extension \"%s\" failed, it will be attempted later.", name);
6705 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006706 default:
6707 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006708 break;
6709 }
6710}
6711
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006712/**
Michal Vaskobb211122015-08-19 14:03:11 +02006713 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006714 *
6715 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006716 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006717 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006718 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006719 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006720int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006721resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006722{
Radek Krejci010e54b2016-03-15 09:40:34 +01006723 uint32_t i, resolved = 0, unres_count, res_count;
PavolVicana0fdbf32017-02-15 17:59:02 +01006724 struct lyxml_elem *yin;
6725 struct yang_type *yang;
Michal Vasko74a60c02017-03-08 10:19:48 +01006726 int rc, log_hidden;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006727
6728 assert(unres);
6729
Michal Vaskoe8734262016-09-29 14:12:06 +02006730 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Michal Vasko74a60c02017-03-08 10:19:48 +01006731 if (*ly_vlog_hide_location()) {
6732 log_hidden = 1;
6733 } else {
6734 log_hidden = 0;
6735 ly_vlog_hide(1);
6736 }
Michal Vasko51054ca2015-08-12 12:20:00 +02006737
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006738 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006739 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006740 unres_count = 0;
6741 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006742
6743 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006744 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006745 * if-features are resolved here to make sure that we will have all if-features for
6746 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006747 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006748 continue;
6749 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006750 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejci818b0c52016-11-09 15:10:51 +01006751 * UNRES_AUGMENT, UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006752
Michal Vasko88c29542015-11-27 14:57:53 +01006753 ++unres_count;
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006754 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 +02006755 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006756 unres->type[i] = UNRES_RESOLVED;
6757 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006758 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006759 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006760 if (!log_hidden) {
6761 ly_vlog_hide(0);
6762 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006763 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006764 ly_err_repeat();
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006765 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006766 } else {
6767 /* forward reference, erase ly_errno */
Radek Krejci00a0e712016-10-26 10:24:46 +02006768 ly_err_clean(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006769 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006770 }
Michal Vasko88c29542015-11-27 14:57:53 +01006771 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006772
Michal Vasko88c29542015-11-27 14:57:53 +01006773 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006774 /* just print the errors */
Michal Vasko74a60c02017-03-08 10:19:48 +01006775 if (!log_hidden) {
6776 ly_vlog_hide(0);
6777 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006778
6779 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006780 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006781 continue;
6782 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006783 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 +01006784 if (unres->type[i] == UNRES_TYPE_DER_EXT) {
PavolVicana0fdbf32017-02-15 17:59:02 +01006785 yin = (struct lyxml_elem*)((struct lys_type *)unres->item[i])->der;
6786 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6787 yang =(struct yang_type *)yin;
6788 ((struct lys_type *)unres->item[i])->base = yang->base;
6789 if (yang->base == LY_TYPE_UNION) {
6790 yang_free_type_union(mod->ctx, (struct lys_type *)unres->item[i]);
6791 }
6792 lydict_remove(mod->ctx, yang->name);
6793 free(yang);
6794 } else {
6795 lyxml_free(mod->ctx, yin);
6796 }
Radek Krejci63fc0962017-02-15 13:20:18 +01006797 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006798 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006799 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006800 }
6801
Radek Krejci07d0fb92017-01-13 14:11:05 +01006802 /* the rest except finalizing extensions */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006803 for (i = 0; i < unres->count; ++i) {
Radek Krejci80056d52017-01-05 13:13:33 +01006804 if (unres->type[i] == UNRES_RESOLVED || unres->type[i] == UNRES_EXT_FINALIZE) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006805 continue;
6806 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006807
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006808 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 +01006809 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006810 if (unres->type[i] == UNRES_LIST_UNIQ) {
6811 /* free the allocated structure */
6812 free(unres->item[i]);
6813 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006814 unres->type[i] = UNRES_RESOLVED;
6815 ++resolved;
6816 } else if (rc == -1) {
Michal Vasko74a60c02017-03-08 10:19:48 +01006817 if (!log_hidden) {
6818 ly_vlog_hide(0);
6819 }
Michal Vasko22af5ca2016-05-20 11:44:02 +02006820 /* print the error */
Radek Krejci791f6c72017-02-22 15:23:39 +01006821 ly_err_repeat();
Michal Vasko22af5ca2016-05-20 11:44:02 +02006822 return -1;
Radek Krejci791f6c72017-02-22 15:23:39 +01006823 } else {
6824 /* forward reference, erase ly_errno */
6825 ly_err_clean(1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006826 }
6827 }
6828
Michal Vasko74a60c02017-03-08 10:19:48 +01006829 if (!log_hidden) {
6830 ly_vlog_hide(0);
6831 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006832
Radek Krejci80056d52017-01-05 13:13:33 +01006833 /* finalize extensions, keep it last to provide the complete schema tree information to the plugin's checkers */
6834 for (i = 0; i < unres->count; ++i) {
6835 if (unres->type[i] != UNRES_EXT_FINALIZE) {
6836 continue;
6837 }
6838
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006839 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 +01006840 unres->type[i] = UNRES_RESOLVED;
Radek Krejci80056d52017-01-05 13:13:33 +01006841 if (rc == 0) {
Radek Krejci80056d52017-01-05 13:13:33 +01006842 ++resolved;
6843 }
Radek Krejci791f6c72017-02-22 15:23:39 +01006844 /* else error - it was already printed, but resolved was not increased,
6845 so this unres item will not be resolved again in the following code,
6846 but it will cause returning -1 at the end, this way we are able to
6847 print all the issues with unres */
Radek Krejci80056d52017-01-05 13:13:33 +01006848 }
6849
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006850 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006851 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6852 * all the validation errors
6853 */
6854 for (i = 0; i < unres->count; ++i) {
6855 if (unres->type[i] == UNRES_RESOLVED) {
6856 continue;
6857 }
Radek Krejcicd9a95a2017-03-25 12:02:35 -05006858 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 +01006859 if (unres->type[i] == UNRES_XPATH) {
Michal Vasko769f8032017-01-24 13:11:55 +01006860 /* XPath referencing an unknown node is actually supposed to be just a warning */
Radek Krejcib3142312016-11-09 11:04:12 +01006861 unres->type[i] = UNRES_RESOLVED;
6862 resolved++;
Radek Krejcib3142312016-11-09 11:04:12 +01006863 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006864 }
Radek Krejcib3142312016-11-09 11:04:12 +01006865 if (resolved < unres->count) {
6866 return -1;
6867 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006868 }
6869
Michal Vaskoe8734262016-09-29 14:12:06 +02006870 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006871 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006872 return EXIT_SUCCESS;
6873}
6874
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006875/**
Michal Vaskobb211122015-08-19 14:03:11 +02006876 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006877 *
6878 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006879 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006880 * @param[in] item Item to resolve. Type determined by \p type.
6881 * @param[in] type Type of the unresolved item.
6882 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006883 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006884 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006885 */
6886int
Radek Krejci48464ed2016-03-17 15:44:09 +01006887unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6888 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006889{
Radek Krejci54081ce2016-08-12 15:21:47 +02006890 int rc;
6891 const char *dictstr;
6892
6893 dictstr = lydict_insert(mod->ctx, str, 0);
6894 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6895
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006896 if (rc < 0) {
Radek Krejci54081ce2016-08-12 15:21:47 +02006897 lydict_remove(mod->ctx, dictstr);
6898 }
6899 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006900}
6901
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006902/**
Michal Vaskobb211122015-08-19 14:03:11 +02006903 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006904 *
6905 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006906 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006907 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006908 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006909 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006910 *
Radek Krejcid9c0ce22017-01-20 15:20:16 +01006911 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error, -2 if the unres item
6912 * is already in the unres list.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006913 */
6914int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006915unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006916 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006917{
Michal Vaskoef486d72016-09-27 12:10:44 +02006918 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006919 struct lyxml_elem *yin;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006920
Michal Vasko9bf425b2015-10-22 11:42:03 +02006921 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6922 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006923
Michal Vasko9e862e82017-03-08 10:20:49 +01006924#ifndef NDEBUG
Radek Krejcidf056df2017-03-09 13:24:45 +01006925 uint32_t u;
6926
Radek Krejci850a5de2016-11-08 14:06:40 +01006927 /* check for duplicities in unres */
6928 for (u = 0; u < unres->count; u++) {
6929 if (unres->type[u] == type && unres->item[u] == item &&
6930 unres->str_snode[u] == snode && unres->module[u] == mod) {
Michal Vasko9e862e82017-03-08 10:20:49 +01006931 /* duplication, should not happen */
6932 assert(0);
Radek Krejci850a5de2016-11-08 14:06:40 +01006933 }
6934 }
Michal Vasko9e862e82017-03-08 10:20:49 +01006935#endif
Radek Krejci850a5de2016-11-08 14:06:40 +01006936
Radek Krejcic293bac2017-02-27 11:25:28 +01006937 if (type == UNRES_EXT_FINALIZE) {
Radek Krejci80056d52017-01-05 13:13:33 +01006938 /* extension finalization is not even tried when adding the item into the inres list */
Radek Krejcic293bac2017-02-27 11:25:28 +01006939 rc = EXIT_FAILURE;
6940 } else {
Radek Krejci80056d52017-01-05 13:13:33 +01006941 if (*ly_vlog_hide_location()) {
6942 log_hidden = 1;
6943 } else {
6944 log_hidden = 0;
6945 ly_vlog_hide(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01006946 }
Radek Krejcicbba57c2017-01-24 13:43:20 +01006947 rc = resolve_unres_schema_item(mod, item, type, snode, unres, 0);
Radek Krejci80056d52017-01-05 13:13:33 +01006948 if (!log_hidden) {
6949 ly_vlog_hide(0);
6950 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006951
Radek Krejci80056d52017-01-05 13:13:33 +01006952 if (rc != EXIT_FAILURE) {
Michal Vaskobb520442017-05-23 10:55:18 +02006953 if (rc == -1) {
Radek Krejci80056d52017-01-05 13:13:33 +01006954 ly_err_repeat();
6955 }
6956 if (type == UNRES_LIST_UNIQ) {
6957 /* free the allocated structure */
6958 free(item);
6959 } else if (rc == -1 && type == UNRES_IFFEAT) {
6960 /* free the allocated resources */
6961 free(*((char **)item));
Michal Vaskobb520442017-05-23 10:55:18 +02006962 }
Radek Krejci80056d52017-01-05 13:13:33 +01006963 return rc;
6964 } else {
6965 /* erase info about validation errors */
6966 ly_err_clean(1);
6967 }
Michal Vaskof02e3742015-08-05 16:27:02 +02006968
Radek Krejci80056d52017-01-05 13:13:33 +01006969 print_unres_schema_item_fail(item, type, snode);
6970
6971 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
6972 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
6973 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
6974 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6975 lyxml_unlink_elem(mod->ctx, yin, 1);
6976 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6977 }
Pavol Vicana0e4e672016-02-24 12:20:04 +01006978 }
Michal Vasko88c29542015-11-27 14:57:53 +01006979 }
6980
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006981 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006982 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006983 LY_CHECK_ERR_RETURN(!unres->item, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006984 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006985 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006986 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006987 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006988 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006989 LY_CHECK_ERR_RETURN(!unres->str_snode, LOGMEM, -1);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006990 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006991 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
Radek Krejcia8d111f2017-05-31 13:57:37 +02006992 LY_CHECK_ERR_RETURN(!unres->module, LOGMEM, -1);
Radek Krejcic071c542016-01-27 14:57:51 +01006993 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006994
Michal Vasko3767fb22016-07-21 12:10:57 +02006995 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006996}
6997
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006998/**
Michal Vaskobb211122015-08-19 14:03:11 +02006999 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007000 *
7001 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02007002 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007003 * @param[in] item Old item to be resolved.
7004 * @param[in] type Type of the old unresolved item.
7005 * @param[in] new_item New item to use in the duplicate.
7006 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02007007 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007008 */
Michal Vaskodad19402015-08-06 09:51:53 +02007009int
Michal Vasko0bd29d12015-08-19 11:45:49 +02007010unres_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 +02007011{
7012 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007013 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007014 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007015
Michal Vaskocf024702015-10-08 15:01:42 +02007016 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007017
Radek Krejcid09d1a52016-08-11 14:05:45 +02007018 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
7019 if (type == UNRES_LIST_UNIQ) {
7020 aux_uniq.list = item;
7021 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
7022 item = &aux_uniq;
7023 }
Michal Vasko878e38d2016-09-05 12:17:53 +02007024 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007025
7026 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007027 if (type == UNRES_LIST_UNIQ) {
7028 free(new_item);
7029 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02007030 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007031 }
7032
Radek Krejcic79c6b12016-07-26 15:11:49 +02007033 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02007034 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01007035 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007036 LOGINT;
7037 return -1;
7038 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02007039 } else if (type == UNRES_IFFEAT) {
7040 /* duplicate unres_iffeature_data */
7041 iff_data = malloc(sizeof *iff_data);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007042 LY_CHECK_ERR_RETURN(!iff_data, LOGMEM, -1);
Radek Krejcicbb473e2016-09-16 14:48:32 +02007043 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
7044 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
7045 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
7046 LOGINT;
7047 return -1;
7048 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007049 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01007050 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02007051 LOGINT;
7052 return -1;
7053 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007054 }
Michal Vaskodad19402015-08-06 09:51:53 +02007055
7056 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007057}
7058
Michal Vaskof02e3742015-08-05 16:27:02 +02007059/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007060int
Michal Vasko878e38d2016-09-05 12:17:53 +02007061unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007062{
Michal Vasko878e38d2016-09-05 12:17:53 +02007063 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007064 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007065
Radek Krejciddddd0d2017-01-20 15:20:46 +01007066 if (start_on_backwards >= 0) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007067 i = start_on_backwards;
7068 } else {
7069 i = unres->count - 1;
7070 }
7071 for (; i > -1; i--) {
7072 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007073 continue;
7074 }
7075 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02007076 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007077 break;
7078 }
7079 } else {
7080 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
7081 aux_uniq2 = (struct unres_list_uniq *)item;
7082 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02007083 break;
7084 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007085 }
7086 }
7087
Michal Vasko878e38d2016-09-05 12:17:53 +02007088 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007089}
Michal Vasko8bcdf292015-08-19 14:04:43 +02007090
Michal Vaskoede9c472016-06-07 09:38:15 +02007091static void
7092unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
7093{
7094 struct lyxml_elem *yin;
7095 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02007096 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02007097
7098 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02007099 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007100 case UNRES_TYPE_DER:
7101 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
7102 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
7103 yang =(struct yang_type *)yin;
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007104 ((struct lys_type *)unres->item[i])->base = yang->base;
Michal Vaskoede9c472016-06-07 09:38:15 +02007105 lydict_remove(ctx, yang->name);
7106 free(yang);
Pavol Vicancf2af4d2016-12-21 14:13:06 +01007107 if (((struct lys_type *)unres->item[i])->base == LY_TYPE_UNION) {
7108 yang_free_type_union(ctx, (struct lys_type *)unres->item[i]);
7109 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007110 } else {
7111 lyxml_free(ctx, yin);
7112 }
7113 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02007114 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02007115 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
7116 lydict_remove(ctx, iff_data->fname);
7117 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02007118 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007119 case UNRES_IDENT:
7120 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02007121 case UNRES_CHOICE_DFLT:
7122 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02007123 lydict_remove(ctx, (const char *)unres->str_snode[i]);
7124 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02007125 case UNRES_LIST_UNIQ:
7126 free(unres->item[i]);
7127 break;
PavolVicanc1807262017-01-31 18:00:27 +01007128 case UNRES_EXT:
7129 free(unres->str_snode[i]);
7130 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02007131 default:
7132 break;
7133 }
7134 unres->type[i] = UNRES_RESOLVED;
7135}
7136
Michal Vasko88c29542015-11-27 14:57:53 +01007137void
Michal Vasko44ab1462017-05-18 13:18:36 +02007138unres_schema_free(struct lys_module *module, struct unres_schema **unres, int all)
Michal Vasko88c29542015-11-27 14:57:53 +01007139{
7140 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01007141 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01007142
Radek Krejcic071c542016-01-27 14:57:51 +01007143 if (!unres || !(*unres)) {
7144 return;
Michal Vasko88c29542015-11-27 14:57:53 +01007145 }
7146
Michal Vasko44ab1462017-05-18 13:18:36 +02007147 assert(module || ((*unres)->count == 0));
Radek Krejcic071c542016-01-27 14:57:51 +01007148
7149 for (i = 0; i < (*unres)->count; ++i) {
Michal Vasko44ab1462017-05-18 13:18:36 +02007150 if (!all && ((*unres)->module[i] != module)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007151 if ((*unres)->type[i] != UNRES_RESOLVED) {
7152 unresolved++;
7153 }
7154 continue;
7155 }
Michal Vaskoede9c472016-06-07 09:38:15 +02007156
7157 /* free heap memory for the specific item */
7158 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01007159 }
7160
Michal Vaskoede9c472016-06-07 09:38:15 +02007161 /* free it all */
Michal Vasko44ab1462017-05-18 13:18:36 +02007162 if (!module || all || (!unresolved && !module->type)) {
Radek Krejcic071c542016-01-27 14:57:51 +01007163 free((*unres)->item);
7164 free((*unres)->type);
7165 free((*unres)->str_snode);
7166 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01007167 free((*unres));
7168 (*unres) = NULL;
7169 }
Michal Vasko88c29542015-11-27 14:57:53 +01007170}
7171
Michal Vasko3cfa3182017-01-17 10:00:58 +01007172static int
7173check_instid_ext_dep(const struct lys_node *sleaf, const char *json_instid)
7174{
7175 struct ly_set *set;
Michal Vasko3c777092017-01-17 14:10:09 +01007176 struct lys_node *op_node, *first_node;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007177 char *buf;
Radek Krejci81c38b82017-06-02 15:04:16 +02007178 int ret = 0;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007179
7180 for (op_node = lys_parent(sleaf);
7181 op_node && !(op_node->nodetype & (LYS_NOTIF | LYS_RPC | LYS_ACTION));
7182 op_node = lys_parent(op_node));
7183
7184 if (op_node && lys_parent(op_node)) {
7185 /* nested operation - any absolute path is external */
7186 return 1;
7187 }
7188
7189 /* get the first node from the instid */
7190 buf = strndup(json_instid, strchr(json_instid + 1, '/') - json_instid);
7191 if (!buf) {
7192 LOGMEM;
7193 return -1;
7194 }
7195
7196 /* there is a predicate, remove it */
7197 if (buf[strlen(buf) - 1] == ']') {
7198 assert(strchr(buf, '['));
7199 *strchr(buf, '[') = '\0';
7200 }
7201
7202 /* find the first schema node */
Michal Vasko50576712017-07-28 12:28:33 +02007203 set = lys_find_path(NULL, sleaf, buf);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007204 if (!set || !set->number) {
7205 free(buf);
Michal Vasko29fd9742017-01-23 09:55:44 +01007206 ly_set_free(set);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007207 return 1;
7208 }
7209 free(buf);
7210
Michal Vasko3c777092017-01-17 14:10:09 +01007211 first_node = set->set.s[0];
Michal Vasko3c777092017-01-17 14:10:09 +01007212
Michal Vasko3cfa3182017-01-17 10:00:58 +01007213 /* based on the first schema node in the path we can decide whether it points to an external tree or not */
7214
7215 if (op_node) {
7216 /* it is an operation, so we're good if it points somewhere inside it */
Michal Vasko3c777092017-01-17 14:10:09 +01007217 if (op_node == first_node) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007218 assert(set->number == 1);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007219 } else {
Radek Krejci81c38b82017-06-02 15:04:16 +02007220 ret = 1;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007221 }
7222 }
7223
Radek Krejci81c38b82017-06-02 15:04:16 +02007224 /* cleanup */
7225 ly_set_free(set);
7226
Michal Vasko3cfa3182017-01-17 10:00:58 +01007227 /* we cannot know whether it points to a tree that is going to be unlinked (application must handle
7228 * this itself), so we say it's not external */
Radek Krejci81c38b82017-06-02 15:04:16 +02007229 return ret;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007230}
7231
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007232/**
7233 * @brief Resolve instance-identifier in JSON data format. Logs directly.
7234 *
7235 * @param[in] data Data node where the path is used
7236 * @param[in] path Instance-identifier node value.
7237 * @param[in,out] ret Resolved instance or NULL.
7238 *
7239 * @return 0 on success (even if unresolved and \p ret is NULL), -1 on error.
7240 */
7241static int
7242resolve_instid(struct lyd_node *data, const char *path, int req_inst, struct lyd_node **ret)
7243{
7244 int i = 0, j;
7245 const struct lys_module *mod;
7246 struct ly_ctx *ctx = data->schema->module->ctx;
7247 const char *model, *name;
7248 char *str;
7249 int mod_len, name_len, has_predicate;
7250 struct unres_data node_match;
7251
7252 memset(&node_match, 0, sizeof node_match);
7253 *ret = NULL;
7254
7255 /* we need root to resolve absolute path */
7256 for (; data->parent; data = data->parent);
7257 /* we're still parsing it and the pointer is not correct yet */
7258 if (data->prev) {
7259 for (; data->prev->next; data = data->prev);
7260 }
7261
7262 /* search for the instance node */
7263 while (path[i]) {
7264 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
7265 if (j <= 0) {
7266 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
7267 goto error;
7268 }
7269 i += j;
7270
7271 str = strndup(model, mod_len);
7272 if (!str) {
7273 LOGMEM;
7274 goto error;
7275 }
7276 mod = ly_ctx_get_module(ctx, str, NULL);
Michal Vaskof53187d2017-01-13 13:23:14 +01007277 if (ctx->data_clb) {
7278 if (!mod) {
7279 mod = ctx->data_clb(ctx, str, NULL, 0, ctx->data_clb_data);
7280 } else if (!mod->implemented) {
7281 mod = ctx->data_clb(ctx, mod->name, mod->ns, LY_MODCLB_NOT_IMPLEMENTED, ctx->data_clb_data);
7282 }
7283 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007284 free(str);
7285
Michal Vaskof53187d2017-01-13 13:23:14 +01007286 if (!mod || !mod->implemented || mod->disabled) {
7287 break;
7288 }
7289
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007290 if (resolve_data(mod, name, name_len, data, &node_match)) {
7291 /* no instance exists */
7292 break;
7293 }
7294
7295 if (has_predicate) {
7296 /* we have predicate, so the current results must be list or leaf-list */
Michal Vasko1c007172017-03-10 10:20:44 +01007297 j = resolve_instid_predicate(&path[i], &node_match);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007298 if (j < 1) {
7299 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
7300 goto error;
7301 }
7302 i += j;
7303
7304 if (!node_match.count) {
7305 /* no instance exists */
7306 break;
7307 }
Michal Vasko6f28e0f2017-04-18 15:14:13 +02007308 } else if (node_match.count) {
7309 /* check that we are not addressing lists */
7310 for (j = 0; (unsigned)j < node_match.count; ++j) {
7311 if (node_match.node[j]->schema->nodetype == LYS_LIST) {
7312 unres_data_del(&node_match, j--);
7313 }
7314 }
7315 if (!node_match.count) {
7316 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing list keys.");
7317 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007318 }
7319 }
7320
7321 if (!node_match.count) {
7322 /* no instance exists */
7323 if (req_inst > -1) {
7324 LOGVAL(LYE_NOREQINS, LY_VLOG_NONE, NULL, path);
7325 return EXIT_FAILURE;
7326 }
7327 LOGVRB("There is no instance of \"%s\", but it is not required.", path);
7328 return EXIT_SUCCESS;
7329 } else if (node_match.count > 1) {
7330 /* instance identifier must resolve to a single node */
7331 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
7332 goto error;
7333 } else {
7334 /* we have required result, remember it and cleanup */
7335 *ret = node_match.node[0];
7336 free(node_match.node);
7337 return EXIT_SUCCESS;
7338 }
7339
7340error:
7341 /* cleanup */
7342 free(node_match.node);
7343 return -1;
7344}
7345
7346static int
7347resolve_leafref(struct lyd_node_leaf_list *leaf, const char *path, int req_inst, struct lyd_node **ret)
Radek Krejci7de36cf2016-09-12 16:18:50 +02007348{
Michal Vasko86ae1f22017-07-10 11:50:33 +02007349 struct ly_set *set;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007350 uint32_t i;
7351
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007352 *ret = NULL;
Radek Krejci7de36cf2016-09-12 16:18:50 +02007353
Michal Vasko86ae1f22017-07-10 11:50:33 +02007354 /* syntax was already checked, so just evaluate the path using standard XPath */
Michal Vasko50576712017-07-28 12:28:33 +02007355 set = lyd_find_path((struct lyd_node *)leaf, path);
Michal Vasko86ae1f22017-07-10 11:50:33 +02007356 if (!set) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007357 return -1;
7358 }
7359
Michal Vasko86ae1f22017-07-10 11:50:33 +02007360 for (i = 0; i < set->number; ++i) {
7361 if (!(set->set.d[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
7362 continue;
7363 }
7364
Radek Krejci1899d6a2016-11-03 13:48:07 +01007365 /* not that the value is already in canonical form since the parsers does the conversion,
7366 * so we can simply compare just the values */
Michal Vasko86ae1f22017-07-10 11:50:33 +02007367 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 +01007368 /* we have the match */
Michal Vasko86ae1f22017-07-10 11:50:33 +02007369 *ret = set->set.d[i];
Radek Krejci7de36cf2016-09-12 16:18:50 +02007370 break;
7371 }
7372 }
7373
Michal Vasko86ae1f22017-07-10 11:50:33 +02007374 ly_set_free(set);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007375
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007376 if (!*ret) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007377 /* reference not found */
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007378 if (req_inst > -1) {
7379 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, path, leaf->value_str);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007380 return EXIT_FAILURE;
7381 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007382 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 +02007383 }
7384 }
7385
7386 return EXIT_SUCCESS;
7387}
7388
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007389/* 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 +01007390int
7391resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type, int store, int ignore_fail,
7392 struct lys_type **resolved_type)
Radek Krejci9b6aad22016-09-20 15:55:51 +02007393{
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007394 struct lys_type *t;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007395 struct lyd_node *ret;
7396 int found, hidden, success = 0, ext_dep, req_inst;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007397 const char *json_val = NULL;
Radek Krejci9b6aad22016-09-20 15:55:51 +02007398
7399 assert(type->base == LY_TYPE_UNION);
7400
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007401 if ((leaf->value_type == LY_TYPE_UNION) || (leaf->value_type == (LY_TYPE_INST | LY_TYPE_INST_UNRES))) {
7402 /* either NULL or instid previously converted to JSON */
7403 json_val = leaf->value.string;
7404 }
Michal Vasko1c8567a2017-01-05 13:42:27 +01007405
Michal Vaskofd6c6502017-01-06 12:15:41 +01007406 if (store) {
7407 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7408 free(leaf->value.bit);
7409 }
7410 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vasko1c8567a2017-01-05 13:42:27 +01007411 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007412
7413 /* turn logging off, we are going to try to validate the value with all the types in order */
7414 hidden = *ly_vlog_hide_location();
7415 ly_vlog_hide(1);
7416
7417 t = NULL;
7418 found = 0;
7419 while ((t = lyp_get_next_union_type(type, t, &found))) {
7420 found = 0;
7421
7422 switch (t->base) {
7423 case LY_TYPE_LEAFREF:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007424 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7425 req_inst = -1;
7426 } else {
7427 req_inst = t->info.lref.req;
7428 }
7429
7430 if (!resolve_leafref(leaf, t->info.lref.path, req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007431 if (store) {
7432 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
7433 /* valid resolved */
7434 leaf->value.leafref = ret;
7435 leaf->value_type = LY_TYPE_LEAFREF;
7436 } else {
7437 /* valid unresolved */
Radek Krejcia571d942017-02-24 09:26:49 +01007438 if (!lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007439 return -1;
7440 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007441 }
7442 }
7443
7444 success = 1;
7445 }
7446 break;
7447 case LY_TYPE_INST:
Michal Vasko3cfa3182017-01-17 10:00:58 +01007448 ext_dep = check_instid_ext_dep(leaf->schema, (json_val ? json_val : leaf->value_str));
7449 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7450 req_inst = -1;
7451 } else {
7452 req_inst = t->info.inst.req;
7453 }
7454
Michal Vaskod3a03112017-01-23 09:56:02 +01007455 if (!resolve_instid((struct lyd_node *)leaf, (json_val ? json_val : leaf->value_str), req_inst, &ret)) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007456 if (store) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007457 if (ret && !ext_dep) {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007458 /* valid resolved */
7459 leaf->value.instance = ret;
7460 leaf->value_type = LY_TYPE_INST;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007461
Michal Vaskofd6c6502017-01-06 12:15:41 +01007462 if (json_val) {
7463 lydict_remove(leaf->schema->module->ctx, leaf->value_str);
7464 leaf->value_str = json_val;
7465 json_val = NULL;
7466 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007467 } else {
Michal Vaskofd6c6502017-01-06 12:15:41 +01007468 /* valid unresolved */
7469 if (json_val) {
7470 /* put the JSON val back */
7471 leaf->value.string = json_val;
7472 json_val = NULL;
7473 } else {
7474 leaf->value.instance = NULL;
7475 }
7476 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007477 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007478 }
7479
7480 success = 1;
7481 }
7482 break;
7483 default:
Radek Krejcia571d942017-02-24 09:26:49 +01007484 if (lyp_parse_value(t, &leaf->value_str, NULL, leaf, NULL, store, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007485 success = 1;
7486 }
7487 break;
7488 }
7489
7490 if (success) {
7491 break;
7492 }
7493
7494 /* erase information about errors - they are false or irrelevant
7495 * and will be replaced by a single error messages */
7496 ly_err_clean(1);
7497
7498 /* erase possible present and invalid value data */
Michal Vaskofd6c6502017-01-06 12:15:41 +01007499 if (store) {
7500 if (t->base == LY_TYPE_BITS) {
7501 free(leaf->value.bit);
7502 }
7503 memset(&leaf->value, 0, sizeof leaf->value);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007504 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007505 }
7506
7507 /* turn logging back on */
7508 if (!hidden) {
7509 ly_vlog_hide(0);
7510 }
7511
7512 if (json_val) {
7513 if (!success) {
7514 /* put the value back for now */
7515 assert(leaf->value_type == LY_TYPE_UNION);
7516 leaf->value.string = json_val;
7517 } else {
7518 /* value was ultimately useless, but we could not have known */
7519 lydict_remove(leaf->schema->module->ctx, json_val);
7520 }
7521 }
7522
Michal Vaskofd6c6502017-01-06 12:15:41 +01007523 if (success) {
7524 if (resolved_type) {
7525 *resolved_type = t;
7526 }
7527 } else if (!ignore_fail || !type->info.uni.has_ptr_type) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007528 /* not found and it is required */
7529 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, leaf->value_str ? leaf->value_str : "", leaf->schema->name);
Radek Krejci9b6aad22016-09-20 15:55:51 +02007530 return EXIT_FAILURE;
7531 }
7532
7533 return EXIT_SUCCESS;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007534
Radek Krejci9b6aad22016-09-20 15:55:51 +02007535}
7536
Michal Vasko8bcdf292015-08-19 14:04:43 +02007537/**
7538 * @brief Resolve a single unres data item. Logs directly.
7539 *
Michal Vaskocf024702015-10-08 15:01:42 +02007540 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02007541 * @param[in] type Type of the unresolved item.
Michal Vasko3cfa3182017-01-17 10:00:58 +01007542 * @param[in] ignore_fail 0 - no, 1 - yes, 2 - yes, but only for external dependencies.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007543 *
7544 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
7545 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02007546int
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007547resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type, int ignore_fail)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007548{
Michal Vasko3cfa3182017-01-17 10:00:58 +01007549 int rc, req_inst, ext_dep;
Michal Vasko83a6c462015-10-08 16:43:53 +02007550 struct lyd_node_leaf_list *leaf;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007551 struct lyd_node *ret;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007552 struct lys_node_leaf *sleaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007553
Michal Vasko83a6c462015-10-08 16:43:53 +02007554 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02007555 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007556
Michal Vaskocf024702015-10-08 15:01:42 +02007557 switch (type) {
7558 case UNRES_LEAFREF:
7559 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007560 assert(leaf->validity & LYD_VAL_LEAFREF);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007561 if ((ignore_fail == 1) || ((leaf->schema->flags & LYS_LEAFREF_DEP) && (ignore_fail == 2))) {
7562 req_inst = -1;
7563 } else {
7564 req_inst = sleaf->type.info.lref.req;
7565 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007566 rc = resolve_leafref(leaf, sleaf->type.info.lref.path, req_inst, &ret);
7567 if (!rc) {
Michal Vaskob1ac8722017-01-02 13:04:25 +01007568 if (ret && !(leaf->schema->flags & LYS_LEAFREF_DEP)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007569 /* valid resolved */
Michal Vasko1c8567a2017-01-05 13:42:27 +01007570 if ((leaf->value_type & LY_DATA_TYPE_MASK) == LY_TYPE_BITS) {
7571 free(leaf->value.bit);
7572 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007573 leaf->value.leafref = ret;
7574 leaf->value_type = LY_TYPE_LEAFREF;
7575 } else {
7576 /* valid unresolved */
7577 if (!(leaf->value_type & LY_TYPE_LEAFREF_UNRES)) {
Radek Krejcia571d942017-02-24 09:26:49 +01007578 if (!lyp_parse_value(&sleaf->type, &leaf->value_str, NULL, leaf, NULL, 1, 0)) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007579 return -1;
7580 }
7581 }
7582 }
7583 leaf->validity &= ~LYD_VAL_LEAFREF;
7584 } else {
7585 return rc;
7586 }
7587 break;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007588
Michal Vaskocf024702015-10-08 15:01:42 +02007589 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02007590 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko3cfa3182017-01-17 10:00:58 +01007591 ext_dep = check_instid_ext_dep(leaf->schema, leaf->value_str);
7592 if (ext_dep == -1) {
7593 return -1;
7594 }
7595
7596 if ((ignore_fail == 1) || (ext_dep && (ignore_fail == 2))) {
7597 req_inst = -1;
7598 } else {
7599 req_inst = sleaf->type.info.inst.req;
7600 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007601 rc = resolve_instid(node, leaf->value_str, req_inst, &ret);
7602 if (!rc) {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007603 if (ret && !ext_dep) {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007604 /* valid resolved */
7605 leaf->value.instance = ret;
7606 leaf->value_type = LY_TYPE_INST;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007607 } else {
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007608 /* valid unresolved */
7609 leaf->value.instance = NULL;
7610 leaf->value_type = LY_TYPE_INST | LY_TYPE_INST_UNRES;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007611 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007612 } else {
7613 return rc;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007614 }
Michal Vaskocf024702015-10-08 15:01:42 +02007615 break;
7616
Radek Krejci7de36cf2016-09-12 16:18:50 +02007617 case UNRES_UNION:
7618 assert(sleaf->type.base == LY_TYPE_UNION);
Michal Vaskofd6c6502017-01-06 12:15:41 +01007619 return resolve_union(leaf, &sleaf->type, 1, ignore_fail, NULL);
Radek Krejci7de36cf2016-09-12 16:18:50 +02007620
Michal Vaskocf024702015-10-08 15:01:42 +02007621 case UNRES_WHEN:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007622 if ((rc = resolve_when(node, NULL, ignore_fail))) {
Michal Vaskocf024702015-10-08 15:01:42 +02007623 return rc;
7624 }
7625 break;
7626
Michal Vaskobf19d252015-10-08 15:39:17 +02007627 case UNRES_MUST:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007628 if ((rc = resolve_must(node, 0, ignore_fail))) {
Michal Vaskoc8c810c2016-09-15 14:02:00 +02007629 return rc;
7630 }
7631 break;
7632
7633 case UNRES_MUST_INOUT:
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007634 if ((rc = resolve_must(node, 1, ignore_fail))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02007635 return rc;
7636 }
7637 break;
7638
Michal Vaskocf024702015-10-08 15:01:42 +02007639 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02007640 LOGINT;
7641 return -1;
7642 }
7643
7644 return EXIT_SUCCESS;
7645}
7646
7647/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01007648 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02007649 *
7650 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02007651 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007652 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01007653 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02007654 */
7655int
Radek Krejci0b7704f2016-03-18 12:16:14 +01007656unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02007657{
Radek Krejci03b71f72016-03-16 11:10:09 +01007658 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02007659 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Radek Krejcibacc7442016-10-27 13:39:56 +02007660 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION));
Michal Vasko8bcdf292015-08-19 14:04:43 +02007661
Radek Krejci03b71f72016-03-16 11:10:09 +01007662 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01007663 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007664 LY_CHECK_ERR_RETURN(!unres->node, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007665 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01007666 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
Radek Krejcia8d111f2017-05-31 13:57:37 +02007667 LY_CHECK_ERR_RETURN(!unres->type, LOGMEM, -1);
Michal Vaskocf024702015-10-08 15:01:42 +02007668 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02007669
Radek Krejci0b7704f2016-03-18 12:16:14 +01007670 if (type == UNRES_WHEN) {
7671 /* remove previous result */
7672 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007673 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007674
7675 return EXIT_SUCCESS;
7676}
7677
7678/**
7679 * @brief Resolve every unres data item in the structure. Logs directly.
7680 *
Radek Krejci082c84f2016-10-17 16:33:06 +02007681 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
7682 * unresolved leafrefs/instids are accepted).
7683 *
7684 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
7685 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007686 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02007687 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
7688 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007689 *
7690 * @return EXIT_SUCCESS on success, -1 on error.
7691 */
7692int
Radek Krejci082c84f2016-10-17 16:33:06 +02007693resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007694{
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007695 uint32_t i, j, first, resolved, del_items, stmt_count;
Michal Vasko3cfa3182017-01-17 10:00:58 +01007696 int rc, progress, ignore_fail;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007697 struct lyd_node *parent;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007698
Radek Krejci082c84f2016-10-17 16:33:06 +02007699 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01007700 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01007701
7702 if (!unres->count) {
7703 return EXIT_SUCCESS;
7704 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007705
Michal Vaskoad2e44a2017-01-03 10:31:35 +01007706 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 +01007707 ignore_fail = 1;
7708 } else if (options & LYD_OPT_NOEXTDEPS) {
7709 ignore_fail = 2;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007710 } else {
Michal Vasko3cfa3182017-01-17 10:00:58 +01007711 ignore_fail = 0;
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007712 }
7713
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007714 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01007715 ly_vlog_hide(1);
7716
Radek Krejci0b7704f2016-03-18 12:16:14 +01007717 /* when-stmt first */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007718 first = 1;
7719 stmt_count = 0;
7720 resolved = 0;
7721 del_items = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01007722 do {
Radek Krejci00a0e712016-10-26 10:24:46 +02007723 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007724 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02007725 for (i = 0; i < unres->count; i++) {
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007726 if (unres->type[i] != UNRES_WHEN) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007727 continue;
7728 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007729 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007730 /* count when-stmt nodes in unres list */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007731 stmt_count++;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007732 }
7733
7734 /* resolve when condition only when all parent when conditions are already resolved */
7735 for (parent = unres->node[i]->parent;
7736 parent && LYD_WHEN_DONE(parent->when_status);
7737 parent = parent->parent) {
7738 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
7739 /* the parent node was already unlinked, do not resolve this node,
7740 * it will be removed anyway, so just mark it as resolved
7741 */
7742 unres->node[i]->when_status |= LYD_WHEN_FALSE;
7743 unres->type[i] = UNRES_RESOLVED;
7744 resolved++;
7745 break;
7746 }
7747 }
7748 if (parent) {
7749 continue;
7750 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007751
Michal Vasko3cfa3182017-01-17 10:00:58 +01007752 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007753 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007754 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02007755 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01007756 /* false when condition */
7757 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007758 ly_err_repeat();
Radek Krejci03b71f72016-03-16 11:10:09 +01007759 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007760 } /* follows else */
7761
Michal Vaskoe31d34a2017-03-28 14:50:38 +02007762 /* auto-delete */
7763 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
7764 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
7765
Radek Krejci0c0086a2016-03-24 15:20:28 +01007766 /* only unlink now, the subtree can contain another nodes stored in the unres list */
7767 /* if it has parent non-presence containers that would be empty, we should actually
7768 * remove the container
7769 */
Radek Krejci2537fd32016-09-07 16:22:41 +02007770 for (parent = unres->node[i];
7771 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
7772 parent = parent->parent) {
7773 if (((struct lys_node_container *)parent->parent->schema)->presence) {
7774 /* presence container */
7775 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007776 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007777 if (parent->next || parent->prev != parent) {
7778 /* non empty (the child we are in and we are going to remove is not the only child) */
7779 break;
7780 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007781 }
Radek Krejci2537fd32016-09-07 16:22:41 +02007782 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01007783
Radek Krejci0c0086a2016-03-24 15:20:28 +01007784 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007785 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01007786 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007787
Radek Krejci0b7704f2016-03-18 12:16:14 +01007788 lyd_unlink(unres->node[i]);
7789 unres->type[i] = UNRES_DELETE;
7790 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01007791
7792 /* update the rest of unres items */
7793 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007794 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007795 continue;
7796 }
7797
7798 /* test if the node is in subtree to be deleted */
7799 for (parent = unres->node[j]; parent; parent = parent->parent) {
7800 if (parent == unres->node[i]) {
7801 /* yes, it is */
7802 unres->type[j] = UNRES_RESOLVED;
7803 resolved++;
7804 break;
7805 }
7806 }
7807 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007808 } else {
7809 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007810 }
Radek Krejci00a0e712016-10-26 10:24:46 +02007811 ly_err_clean(1);
Radek Krejci010e54b2016-03-15 09:40:34 +01007812 resolved++;
7813 progress = 1;
7814 } else if (rc == -1) {
7815 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007816 /* print only this last error */
Michal Vasko3cfa3182017-01-17 10:00:58 +01007817 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Radek Krejci010e54b2016-03-15 09:40:34 +01007818 return -1;
Radek Krejci2467a492016-10-24 15:16:59 +02007819 } /* else forward reference */
Radek Krejci010e54b2016-03-15 09:40:34 +01007820 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007821 first = 0;
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007822 } while (progress && resolved < stmt_count);
Radek Krejci010e54b2016-03-15 09:40:34 +01007823
Radek Krejci0b7704f2016-03-18 12:16:14 +01007824 /* do we have some unresolved when-stmt? */
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007825 if (stmt_count > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007826 ly_vlog_hide(0);
Radek Krejci2467a492016-10-24 15:16:59 +02007827 ly_err_repeat();
Radek Krejci0b7704f2016-03-18 12:16:14 +01007828 return -1;
7829 }
7830
7831 for (i = 0; del_items && i < unres->count; i++) {
7832 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7833 if (unres->type[i] != UNRES_DELETE) {
7834 continue;
7835 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007836 if (!unres->node[i]) {
7837 unres->type[i] = UNRES_RESOLVED;
7838 del_items--;
7839 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007840 }
7841
7842 /* really remove the complete subtree */
7843 lyd_free(unres->node[i]);
7844 unres->type[i] = UNRES_RESOLVED;
7845 del_items--;
7846 }
Michal Vaskoc35d2a72017-05-09 14:21:30 +02007847
7848 /* now leafrefs */
7849 first = 1;
7850 stmt_count = 0;
7851 resolved = 0;
7852 do {
7853 progress = 0;
7854 for (i = 0; i < unres->count; i++) {
7855 if (unres->type[i] != UNRES_LEAFREF) {
7856 continue;
7857 }
7858 if (first) {
7859 /* count leafref nodes in unres list */
7860 stmt_count++;
7861 }
7862
7863 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7864 if (!rc) {
7865 unres->type[i] = UNRES_RESOLVED;
7866 ly_err_clean(1);
7867 resolved++;
7868 progress = 1;
7869 } else if (rc == -1) {
7870 ly_vlog_hide(0);
7871 /* print only this last error */
7872 resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
7873 return -1;
7874 } /* else forward reference */
7875 }
7876 first = 0;
7877 } while (progress && resolved < stmt_count);
7878
7879 /* do we have some unresolved leafrefs? */
7880 if (stmt_count > resolved) {
7881 ly_vlog_hide(0);
7882 ly_err_repeat();
7883 return -1;
7884 }
7885
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007886 ly_vlog_hide(0);
Radek Krejci010e54b2016-03-15 09:40:34 +01007887
7888 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007889 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007890 if (unres->type[i] == UNRES_RESOLVED) {
7891 continue;
7892 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007893 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007894
Michal Vasko3cfa3182017-01-17 10:00:58 +01007895 rc = resolve_unres_data_item(unres->node[i], unres->type[i], ignore_fail);
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007896 if (rc) {
7897 /* since when was already resolved, a forward reference is an error */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007898 return -1;
7899 }
Michal Vaskoe3886bb2017-01-02 11:33:28 +01007900
7901 unres->type[i] = UNRES_RESOLVED;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007902 }
7903
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007904 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007905 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007906 return EXIT_SUCCESS;
7907}