blob: 18c5743f5e3217248a28ef523791634a413cca1c [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"
32
Michal Vaskod24dd012016-09-30 12:20:22 +020033int
34parse_range_dec64(const char **str_num, uint8_t dig, int64_t *num)
Michal Vasko4d1f0482016-09-19 14:35:06 +020035{
36 const char *ptr;
37 int minus = 0;
38 int64_t ret = 0;
39 int8_t str_exp, str_dig = -1;
40
41 ptr = *str_num;
42
43 if (ptr[0] == '-') {
44 minus = 1;
45 ++ptr;
46 }
47
Michal Vaskod24dd012016-09-30 12:20:22 +020048 if (!isdigit(ptr[0])) {
49 /* there must be at least one */
50 return 1;
51 }
52
Michal Vasko4d1f0482016-09-19 14:35:06 +020053 for (str_exp = 0; isdigit(ptr[0]) || ((ptr[0] == '.') && (str_dig < 0)); ++ptr) {
54 if (str_exp > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020055 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020056 }
57
58 if (ptr[0] == '.') {
59 if (ptr[1] == '.') {
60 /* it's the next interval */
61 break;
62 }
63 ++str_dig;
64 } else {
65 ret = ret * 10 + (ptr[0] - 48);
66 if (str_dig > -1) {
67 ++str_dig;
68 }
69 ++str_exp;
70 }
71 }
Michal Vaskod24dd012016-09-30 12:20:22 +020072 if (str_dig == 0) {
73 /* no digits after '.' */
74 return 1;
75 } else if (str_dig == -1) {
76 /* there are 0 numbers after the floating point */
Michal Vasko4d1f0482016-09-19 14:35:06 +020077 str_dig = 0;
78 }
79
80 /* it's parsed, now adjust the number based on fraction-digits, if needed */
81 if (str_dig < dig) {
82 if ((str_exp - 1) + (dig - str_dig) > 18) {
Michal Vaskod24dd012016-09-30 12:20:22 +020083 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020084 }
85 ret *= dec_pow(dig - str_dig);
86 }
87 if (str_dig > dig) {
Michal Vaskod24dd012016-09-30 12:20:22 +020088 return 1;
Michal Vasko4d1f0482016-09-19 14:35:06 +020089 }
90
91 if (minus) {
92 ret *= -1;
93 }
94 *str_num = ptr;
Michal Vaskod24dd012016-09-30 12:20:22 +020095 *num = ret;
Michal Vasko4d1f0482016-09-19 14:35:06 +020096
Michal Vaskod24dd012016-09-30 12:20:22 +020097 return 0;
Michal Vasko4d1f0482016-09-19 14:35:06 +020098}
99
100/**
Radek Krejci6dc53a22015-08-17 13:27:59 +0200101 * @brief Parse an identifier.
102 *
103 * ;; An identifier MUST NOT start with (('X'|'x') ('M'|'m') ('L'|'l'))
104 * identifier = (ALPHA / "_")
105 * *(ALPHA / DIGIT / "_" / "-" / ".")
106 *
Michal Vaskobb211122015-08-19 14:03:11 +0200107 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200108 *
109 * @return Number of characters successfully parsed.
110 */
Michal Vasko249e6b52015-08-19 11:08:52 +0200111int
Radek Krejci6dc53a22015-08-17 13:27:59 +0200112parse_identifier(const char *id)
113{
114 int parsed = 0;
115
Michal Vasko1ab90bc2016-03-15 10:40:22 +0100116 assert(id);
117
Radek Krejci6dc53a22015-08-17 13:27:59 +0200118 if (!isalpha(id[0]) && (id[0] != '_')) {
119 return -parsed;
120 }
121
122 ++parsed;
123 ++id;
124
125 while (isalnum(id[0]) || (id[0] == '_') || (id[0] == '-') || (id[0] == '.')) {
126 ++parsed;
127 ++id;
128 }
129
130 return parsed;
131}
132
133/**
134 * @brief Parse a node-identifier.
135 *
Michal Vasko723e50c2015-10-20 15:20:29 +0200136 * node-identifier = [module-name ":"] identifier
Radek Krejci6dc53a22015-08-17 13:27:59 +0200137 *
Michal Vaskobb211122015-08-19 14:03:11 +0200138 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200139 * @param[out] mod_name Points to the module name, NULL if there is not any.
140 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200141 * @param[out] name Points to the node name.
142 * @param[out] nam_len Length of the node name.
143 *
144 * @return Number of characters successfully parsed,
145 * positive on success, negative on failure.
146 */
147static int
Michal Vasko723e50c2015-10-20 15:20:29 +0200148parse_node_identifier(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200149{
150 int parsed = 0, ret;
151
152 assert(id);
Michal Vasko723e50c2015-10-20 15:20:29 +0200153 if (mod_name) {
154 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200155 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200156 if (mod_name_len) {
157 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200158 }
159 if (name) {
160 *name = NULL;
161 }
162 if (nam_len) {
163 *nam_len = 0;
164 }
165
166 if ((ret = parse_identifier(id)) < 1) {
167 return ret;
168 }
169
Michal Vasko723e50c2015-10-20 15:20:29 +0200170 if (mod_name) {
171 *mod_name = id;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200172 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200173 if (mod_name_len) {
174 *mod_name_len = ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200175 }
176
177 parsed += ret;
178 id += ret;
179
180 /* there is prefix */
181 if (id[0] == ':') {
182 ++parsed;
183 ++id;
184
185 /* there isn't */
186 } else {
Michal Vasko723e50c2015-10-20 15:20:29 +0200187 if (name && mod_name) {
188 *name = *mod_name;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200189 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200190 if (mod_name) {
191 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200192 }
193
Michal Vasko723e50c2015-10-20 15:20:29 +0200194 if (nam_len && mod_name_len) {
195 *nam_len = *mod_name_len;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200196 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200197 if (mod_name_len) {
198 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200199 }
200
201 return parsed;
202 }
203
204 /* identifier (node name) */
205 if ((ret = parse_identifier(id)) < 1) {
206 return -parsed+ret;
207 }
208
209 if (name) {
210 *name = id;
211 }
212 if (nam_len) {
213 *nam_len = ret;
214 }
215
216 return parsed+ret;
217}
218
219/**
220 * @brief Parse a path-predicate (leafref).
221 *
222 * path-predicate = "[" *WSP path-equality-expr *WSP "]"
223 * path-equality-expr = node-identifier *WSP "=" *WSP path-key-expr
224 *
Michal Vaskobb211122015-08-19 14:03:11 +0200225 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200226 * @param[out] prefix Points to the prefix, NULL if there is not any.
227 * @param[out] pref_len Length of the prefix, 0 if there is not any.
228 * @param[out] name Points to the node name.
229 * @param[out] nam_len Length of the node name.
230 * @param[out] path_key_expr Points to the path-key-expr.
231 * @param[out] pke_len Length of the path-key-expr.
232 * @param[out] has_predicate Flag to mark whether there is another predicate following.
233 *
234 * @return Number of characters successfully parsed,
235 * positive on success, negative on failure.
236 */
237static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200238parse_path_predicate(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
239 const char **path_key_expr, int *pke_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200240{
241 const char *ptr;
242 int parsed = 0, ret;
243
244 assert(id);
245 if (prefix) {
246 *prefix = NULL;
247 }
248 if (pref_len) {
249 *pref_len = 0;
250 }
251 if (name) {
252 *name = NULL;
253 }
254 if (nam_len) {
255 *nam_len = 0;
256 }
257 if (path_key_expr) {
258 *path_key_expr = NULL;
259 }
260 if (pke_len) {
261 *pke_len = 0;
262 }
263 if (has_predicate) {
264 *has_predicate = 0;
265 }
266
267 if (id[0] != '[') {
268 return -parsed;
269 }
270
271 ++parsed;
272 ++id;
273
274 while (isspace(id[0])) {
275 ++parsed;
276 ++id;
277 }
278
279 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
280 return -parsed+ret;
281 }
282
283 parsed += ret;
284 id += ret;
285
286 while (isspace(id[0])) {
287 ++parsed;
288 ++id;
289 }
290
291 if (id[0] != '=') {
292 return -parsed;
293 }
294
295 ++parsed;
296 ++id;
297
298 while (isspace(id[0])) {
299 ++parsed;
300 ++id;
301 }
302
303 if ((ptr = strchr(id, ']')) == NULL) {
304 return -parsed;
305 }
306
307 --ptr;
308 while (isspace(ptr[0])) {
309 --ptr;
310 }
311 ++ptr;
312
313 ret = ptr-id;
314 if (path_key_expr) {
315 *path_key_expr = id;
316 }
317 if (pke_len) {
318 *pke_len = ret;
319 }
320
321 parsed += ret;
322 id += ret;
323
324 while (isspace(id[0])) {
325 ++parsed;
326 ++id;
327 }
328
329 assert(id[0] == ']');
330
331 if (id[1] == '[') {
332 *has_predicate = 1;
333 }
334
335 return parsed+1;
336}
337
338/**
339 * @brief Parse a path-key-expr (leafref). First call parses "current()", all
340 * the ".." and the first node-identifier, other calls parse a single
341 * node-identifier each.
342 *
343 * path-key-expr = current-function-invocation *WSP "/" *WSP
344 * rel-path-keyexpr
345 * rel-path-keyexpr = 1*(".." *WSP "/" *WSP)
346 * *(node-identifier *WSP "/" *WSP)
347 * node-identifier
348 *
Michal Vaskobb211122015-08-19 14:03:11 +0200349 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200350 * @param[out] prefix Points to the prefix, NULL if there is not any.
351 * @param[out] pref_len Length of the prefix, 0 if there is not any.
352 * @param[out] name Points to the node name.
353 * @param[out] nam_len Length of the node name.
354 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
355 * must not be changed between consecutive calls.
356 * @return Number of characters successfully parsed,
357 * positive on success, negative on failure.
358 */
359static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200360parse_path_key_expr(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len,
361 int *parent_times)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200362{
363 int parsed = 0, ret, par_times = 0;
364
365 assert(id);
366 assert(parent_times);
367 if (prefix) {
368 *prefix = NULL;
369 }
370 if (pref_len) {
371 *pref_len = 0;
372 }
373 if (name) {
374 *name = NULL;
375 }
376 if (nam_len) {
377 *nam_len = 0;
378 }
379
380 if (!*parent_times) {
381 /* current-function-invocation *WSP "/" *WSP rel-path-keyexpr */
382 if (strncmp(id, "current()", 9)) {
383 return -parsed;
384 }
385
386 parsed += 9;
387 id += 9;
388
389 while (isspace(id[0])) {
390 ++parsed;
391 ++id;
392 }
393
394 if (id[0] != '/') {
395 return -parsed;
396 }
397
398 ++parsed;
399 ++id;
400
401 while (isspace(id[0])) {
402 ++parsed;
403 ++id;
404 }
405
406 /* rel-path-keyexpr */
407 if (strncmp(id, "..", 2)) {
408 return -parsed;
409 }
410 ++par_times;
411
412 parsed += 2;
413 id += 2;
414
415 while (isspace(id[0])) {
416 ++parsed;
417 ++id;
418 }
419 }
420
421 /* 1*(".." *WSP "/" *WSP) *(node-identifier *WSP "/" *WSP) node-identifier
422 *
423 * first parent reference with whitespaces already parsed
424 */
425 if (id[0] != '/') {
426 return -parsed;
427 }
428
429 ++parsed;
430 ++id;
431
432 while (isspace(id[0])) {
433 ++parsed;
434 ++id;
435 }
436
437 while (!strncmp(id, "..", 2) && !*parent_times) {
438 ++par_times;
439
440 parsed += 2;
441 id += 2;
442
443 while (isspace(id[0])) {
444 ++parsed;
445 ++id;
446 }
447
448 if (id[0] != '/') {
449 return -parsed;
450 }
451
452 ++parsed;
453 ++id;
454
455 while (isspace(id[0])) {
456 ++parsed;
457 ++id;
458 }
459 }
460
461 if (!*parent_times) {
462 *parent_times = par_times;
463 }
464
465 /* all parent references must be parsed at this point */
466 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
467 return -parsed+ret;
468 }
469
470 parsed += ret;
471 id += ret;
472
473 return parsed;
474}
475
476/**
477 * @brief Parse path-arg (leafref).
478 *
479 * path-arg = absolute-path / relative-path
480 * absolute-path = 1*("/" (node-identifier *path-predicate))
481 * relative-path = 1*(".." "/") descendant-path
482 *
Michal Vaskobb211122015-08-19 14:03:11 +0200483 * @param[in] id Identifier to use.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200484 * @param[out] prefix Points to the prefix, NULL if there is not any.
485 * @param[out] pref_len Length of the prefix, 0 if there is not any.
486 * @param[out] name Points to the node name.
487 * @param[out] nam_len Length of the node name.
488 * @param[out] parent_times Number of ".." in the path. Must be 0 on the first call,
489 * must not be changed between consecutive calls. -1 if the
490 * path is relative.
491 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
492 *
493 * @return Number of characters successfully parsed,
494 * positive on success, negative on failure.
495 */
496static int
Michal Vasko23b61ec2015-08-19 11:19:50 +0200497parse_path_arg(const char *id, const char **prefix, int *pref_len, const char **name, int *nam_len, int *parent_times,
498 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200499{
500 int parsed = 0, ret, par_times = 0;
501
502 assert(id);
503 assert(parent_times);
504 if (prefix) {
505 *prefix = NULL;
506 }
507 if (pref_len) {
508 *pref_len = 0;
509 }
510 if (name) {
511 *name = NULL;
512 }
513 if (nam_len) {
514 *nam_len = 0;
515 }
516 if (has_predicate) {
517 *has_predicate = 0;
518 }
519
520 if (!*parent_times && !strncmp(id, "..", 2)) {
521 ++par_times;
522
523 parsed += 2;
524 id += 2;
525
526 while (!strncmp(id, "/..", 3)) {
527 ++par_times;
528
529 parsed += 3;
530 id += 3;
531 }
532 }
533
534 if (!*parent_times) {
535 if (par_times) {
536 *parent_times = par_times;
537 } else {
538 *parent_times = -1;
539 }
540 }
541
542 if (id[0] != '/') {
543 return -parsed;
544 }
545
546 /* skip '/' */
547 ++parsed;
548 ++id;
549
550 /* node-identifier ([prefix:]identifier) */
551 if ((ret = parse_node_identifier(id, prefix, pref_len, name, nam_len)) < 1) {
552 return -parsed-ret;
553 }
554
555 parsed += ret;
556 id += ret;
557
558 /* there is no predicate */
559 if ((id[0] == '/') || !id[0]) {
560 return parsed;
561 } else if (id[0] != '[') {
562 return -parsed;
563 }
564
565 if (has_predicate) {
566 *has_predicate = 1;
567 }
568
569 return parsed;
570}
571
572/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200573 * @brief Parse instance-identifier in JSON data format. That means that prefixes
Michal Vaskob2f40be2016-09-08 16:03:48 +0200574 * (which are mandatory for every node-identifier) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200575 *
576 * instance-identifier = 1*("/" (node-identifier *predicate))
577 *
Michal Vaskobb211122015-08-19 14:03:11 +0200578 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200579 * @param[out] model Points to the model name.
580 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200581 * @param[out] name Points to the node name.
582 * @param[out] nam_len Length of the node name.
583 * @param[out] has_predicate Flag to mark whether there is a predicate specified.
584 *
585 * @return Number of characters successfully parsed,
586 * positive on success, negative on failure.
587 */
588static int
Michal Vaskof39142b2015-10-21 11:40:05 +0200589parse_instance_identifier(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
590 int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200591{
592 int parsed = 0, ret;
593
Radek Krejci6dc53a22015-08-17 13:27:59 +0200594 if (has_predicate) {
595 *has_predicate = 0;
596 }
597
598 if (id[0] != '/') {
599 return -parsed;
600 }
601
602 ++parsed;
603 ++id;
604
Michal Vaskob2f40be2016-09-08 16:03:48 +0200605 if ((ret = parse_identifier(id)) < 1) {
606 return ret;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200607 }
608
Michal Vaskob2f40be2016-09-08 16:03:48 +0200609 *model = id;
610 *mod_len = ret;
611
Radek Krejci6dc53a22015-08-17 13:27:59 +0200612 parsed += ret;
613 id += ret;
614
Michal Vaskob2f40be2016-09-08 16:03:48 +0200615 if (id[0] != ':') {
616 return -parsed;
617 }
618
619 ++parsed;
620 ++id;
621
622 if ((ret = parse_identifier(id)) < 1) {
623 return ret;
624 }
625
626 *name = id;
627 *nam_len = ret;
628
629 parsed += ret;
630 id += ret;
631
Radek Krejci4967cb62016-09-14 16:40:28 +0200632 if (id[0] == '[' && has_predicate) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200633 *has_predicate = 1;
634 }
635
636 return parsed;
637}
638
639/**
Michal Vaskof39142b2015-10-21 11:40:05 +0200640 * @brief Parse predicate (instance-identifier) in JSON data format. That means that prefixes
Michal Vasko1f2cc332015-08-19 11:18:32 +0200641 * (which are mandatory) are actually model names.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200642 *
643 * predicate = "[" *WSP (predicate-expr / pos) *WSP "]"
644 * predicate-expr = (node-identifier / ".") *WSP "=" *WSP
645 * ((DQUOTE string DQUOTE) /
646 * (SQUOTE string SQUOTE))
647 * pos = non-negative-integer-value
648 *
Michal Vaskobb211122015-08-19 14:03:11 +0200649 * @param[in] id Identifier to use.
Michal Vasko1f2cc332015-08-19 11:18:32 +0200650 * @param[out] model Points to the model name.
651 * @param[out] mod_len Length of the model name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200652 * @param[out] name Points to the node name. Can be identifier (from node-identifier), "." or pos.
653 * @param[out] nam_len Length of the node name.
654 * @param[out] value Value the node-identifier must have (string from the grammar),
655 * NULL if there is not any.
656 * @param[out] val_len Length of the value, 0 if there is not any.
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_predicate(const char *id, const char **model, int *mod_len, const char **name, int *nam_len,
664 const char **value, int *val_len, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200665{
666 const char *ptr;
667 int parsed = 0, ret;
668 char quote;
669
670 assert(id);
Michal Vasko1f2cc332015-08-19 11:18:32 +0200671 if (model) {
672 *model = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200673 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200674 if (mod_len) {
675 *mod_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200676 }
677 if (name) {
678 *name = NULL;
679 }
680 if (nam_len) {
681 *nam_len = 0;
682 }
683 if (value) {
684 *value = NULL;
685 }
686 if (val_len) {
687 *val_len = 0;
688 }
689 if (has_predicate) {
690 *has_predicate = 0;
691 }
692
693 if (id[0] != '[') {
694 return -parsed;
695 }
696
697 ++parsed;
698 ++id;
699
700 while (isspace(id[0])) {
701 ++parsed;
702 ++id;
703 }
704
705 /* pos */
706 if (isdigit(id[0])) {
707 if (name) {
708 *name = id;
709 }
710
711 if (id[0] == '0') {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200712 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200713 }
714
715 while (isdigit(id[0])) {
716 ++parsed;
717 ++id;
718 }
719
720 if (nam_len) {
721 *nam_len = id-(*name);
722 }
723
Michal Vaskof2f28a12016-09-09 12:43:06 +0200724 /* "." or node-identifier */
Radek Krejci6dc53a22015-08-17 13:27:59 +0200725 } else {
Michal Vaskof2f28a12016-09-09 12:43:06 +0200726 if (id[0] == '.') {
727 if (name) {
728 *name = id;
729 }
730 if (nam_len) {
731 *nam_len = 1;
732 }
733
734 ++parsed;
735 ++id;
736
737 } else {
738 if ((ret = parse_node_identifier(id, model, mod_len, name, nam_len)) < 1) {
739 return -parsed+ret;
740 } else if (model && !*model) {
741 return -parsed;
742 }
743
744 parsed += ret;
745 id += ret;
746 }
747
748 while (isspace(id[0])) {
749 ++parsed;
750 ++id;
751 }
752
753 if (id[0] != '=') {
Michal Vasko1f2cc332015-08-19 11:18:32 +0200754 return -parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200755 }
Michal Vasko1f2cc332015-08-19 11:18:32 +0200756
Radek Krejci6dc53a22015-08-17 13:27:59 +0200757 ++parsed;
758 ++id;
759
Michal Vaskof2f28a12016-09-09 12:43:06 +0200760 while (isspace(id[0])) {
761 ++parsed;
762 ++id;
763 }
764
765 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
766 if ((id[0] == '\"') || (id[0] == '\'')) {
767 quote = id[0];
768
769 ++parsed;
770 ++id;
771
772 if ((ptr = strchr(id, quote)) == NULL) {
773 return -parsed;
774 }
775 ret = ptr-id;
776
777 if (value) {
778 *value = id;
779 }
780 if (val_len) {
781 *val_len = ret;
782 }
783
784 parsed += ret+1;
785 id += ret+1;
786 } else {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200787 return -parsed;
788 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200789 }
790
791 while (isspace(id[0])) {
792 ++parsed;
793 ++id;
794 }
795
796 if (id[0] != ']') {
797 return -parsed;
798 }
799
800 ++parsed;
801 ++id;
802
803 if ((id[0] == '[') && has_predicate) {
804 *has_predicate = 1;
805 }
806
807 return parsed;
808}
809
810/**
811 * @brief Parse schema-nodeid.
812 *
813 * schema-nodeid = absolute-schema-nodeid /
814 * descendant-schema-nodeid
815 * absolute-schema-nodeid = 1*("/" node-identifier)
Michal Vasko48935352016-03-29 11:52:36 +0200816 * descendant-schema-nodeid = ["." "/"]
Radek Krejci6dc53a22015-08-17 13:27:59 +0200817 * node-identifier
818 * absolute-schema-nodeid
819 *
Michal Vaskobb211122015-08-19 14:03:11 +0200820 * @param[in] id Identifier to use.
Michal Vasko723e50c2015-10-20 15:20:29 +0200821 * @param[out] mod_name Points to the module name, NULL if there is not any.
822 * @param[out] mod_name_len Length of the module name, 0 if there is not any.
Michal Vasko48935352016-03-29 11:52:36 +0200823 * @param[out] name Points to the node name.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200824 * @param[out] nam_len Length of the node name.
825 * @param[out] is_relative Flag to mark whether the nodeid is absolute or descendant. Must be -1
826 * on the first call, must not be changed between consecutive calls.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100827 * @param[out] has_predicate Flag to mark whether there is a predicate specified. It cannot be
828 * based on the grammar, in those cases use NULL.
Radek Krejci6dc53a22015-08-17 13:27:59 +0200829 *
830 * @return Number of characters successfully parsed,
831 * positive on success, negative on failure.
832 */
Michal Vasko22448d32016-03-16 13:17:29 +0100833int
Michal Vasko723e50c2015-10-20 15:20:29 +0200834parse_schema_nodeid(const char *id, const char **mod_name, int *mod_name_len, const char **name, int *nam_len,
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100835 int *is_relative, int *has_predicate)
Radek Krejci6dc53a22015-08-17 13:27:59 +0200836{
837 int parsed = 0, ret;
838
839 assert(id);
840 assert(is_relative);
Michal Vasko723e50c2015-10-20 15:20:29 +0200841 if (mod_name) {
842 *mod_name = NULL;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200843 }
Michal Vasko723e50c2015-10-20 15:20:29 +0200844 if (mod_name_len) {
845 *mod_name_len = 0;
Radek Krejci6dc53a22015-08-17 13:27:59 +0200846 }
847 if (name) {
848 *name = NULL;
849 }
850 if (nam_len) {
851 *nam_len = 0;
852 }
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100853 if (has_predicate) {
854 *has_predicate = 0;
855 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200856
857 if (id[0] != '/') {
858 if (*is_relative != -1) {
859 return -parsed;
860 } else {
861 *is_relative = 1;
862 }
Michal Vasko48935352016-03-29 11:52:36 +0200863 if (!strncmp(id, "./", 2)) {
864 parsed += 2;
865 id += 2;
866 }
Radek Krejci6dc53a22015-08-17 13:27:59 +0200867 } else {
868 if (*is_relative == -1) {
869 *is_relative = 0;
870 }
871 ++parsed;
872 ++id;
873 }
874
Michal Vasko723e50c2015-10-20 15:20:29 +0200875 if ((ret = parse_node_identifier(id, mod_name, mod_name_len, name, nam_len)) < 1) {
Radek Krejci6dc53a22015-08-17 13:27:59 +0200876 return -parsed+ret;
877 }
878
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100879 parsed += ret;
880 id += ret;
881
882 if ((id[0] == '[') && has_predicate) {
883 *has_predicate = 1;
884 }
885
886 return parsed;
887}
888
889/**
890 * @brief Parse schema predicate (special format internally used).
891 *
892 * predicate = "[" *WSP predicate-expr *WSP "]"
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200893 * predicate-expr = "." / identifier / key-with-value
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100894 * key-with-value = identifier *WSP "=" *WSP
895 * ((DQUOTE string DQUOTE) /
896 * (SQUOTE string SQUOTE))
897 *
898 * @param[in] id Identifier to use.
899 * @param[out] name Points to the list key name.
900 * @param[out] nam_len Length of \p name.
Michal Vasko22448d32016-03-16 13:17:29 +0100901 * @param[out] value Points to the key value. If specified, key-with-value is expected.
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100902 * @param[out] val_len Length of \p value.
903 * @param[out] has_predicate Flag to mark whether there is another predicate specified.
904 */
Michal Vasko22448d32016-03-16 13:17:29 +0100905int
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200906parse_schema_json_predicate(const char *id, const char **name, int *nam_len, const char **value, int *val_len,
Michal Vasko3547c532016-03-14 09:40:50 +0100907 int *has_predicate)
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100908{
909 const char *ptr;
910 int parsed = 0, ret;
911 char quote;
912
913 assert(id);
914 if (name) {
915 *name = NULL;
916 }
917 if (nam_len) {
918 *nam_len = 0;
919 }
920 if (value) {
921 *value = NULL;
922 }
923 if (val_len) {
924 *val_len = 0;
925 }
926 if (has_predicate) {
927 *has_predicate = 0;
928 }
929
930 if (id[0] != '[') {
931 return -parsed;
932 }
933
934 ++parsed;
935 ++id;
936
937 while (isspace(id[0])) {
938 ++parsed;
939 ++id;
940 }
941
Michal Vasko22448d32016-03-16 13:17:29 +0100942 /* identifier */
Michal Vasko7b54f7e2016-05-03 15:07:31 +0200943 if (id[0] == '.') {
944 ret = 1;
945 } else if ((ret = parse_identifier(id)) < 1) {
Michal Vasko83e8e5b2016-03-11 14:29:10 +0100946 return -parsed + ret;
947 }
948 if (name) {
949 *name = id;
950 }
951 if (nam_len) {
952 *nam_len = ret;
953 }
954
955 parsed += ret;
956 id += ret;
957
958 while (isspace(id[0])) {
959 ++parsed;
960 ++id;
961 }
962
963 /* there is value as well */
964 if (id[0] == '=') {
965 ++parsed;
966 ++id;
967
968 while (isspace(id[0])) {
969 ++parsed;
970 ++id;
971 }
972
973 /* ((DQUOTE string DQUOTE) / (SQUOTE string SQUOTE)) */
974 if ((id[0] == '\"') || (id[0] == '\'')) {
975 quote = id[0];
976
977 ++parsed;
978 ++id;
979
980 if ((ptr = strchr(id, quote)) == NULL) {
981 return -parsed;
982 }
983 ret = ptr - id;
984
985 if (value) {
986 *value = id;
987 }
988 if (val_len) {
989 *val_len = ret;
990 }
991
992 parsed += ret + 1;
993 id += ret + 1;
994 } else {
995 return -parsed;
996 }
997
998 while (isspace(id[0])) {
999 ++parsed;
1000 ++id;
1001 }
Michal Vasko22448d32016-03-16 13:17:29 +01001002 } else if (value) {
1003 /* if value was expected, it's mandatory */
1004 return -parsed;
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001005 }
1006
1007 if (id[0] != ']') {
1008 return -parsed;
1009 }
1010
1011 ++parsed;
1012 ++id;
1013
1014 if ((id[0] == '[') && has_predicate) {
1015 *has_predicate = 1;
1016 }
1017
1018 return parsed;
Radek Krejci6dc53a22015-08-17 13:27:59 +02001019}
1020
1021/**
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001022 * @brief Resolve (find) a feature definition. Logs directly.
1023 *
1024 * @param[in] feat_name Feature name to resolve.
1025 * @param[in] len Length of \p feat_name.
1026 * @param[in] node Node with the if-feature expression.
Radek Krejci9ff0a922016-07-14 13:08:05 +02001027 * @param[out] feature Pointer to be set to point to the feature definition, if feature not found
1028 * (return code 1), the pointer is untouched.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001029 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02001030 * @return 0 on success, 1 on forward reference, -1 on error.
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001031 */
1032static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001033resolve_feature(const char *feat_name, uint16_t len, const struct lys_node *node, struct lys_feature **feature)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001034{
1035 char *str;
1036 const char *mod_name, *name;
1037 int mod_name_len, nam_len, i, j;
1038 const struct lys_module *module;
1039
Radek Krejci9ff0a922016-07-14 13:08:05 +02001040 assert(feature);
1041
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001042 /* check prefix */
1043 if ((i = parse_node_identifier(feat_name, &mod_name, &mod_name_len, &name, &nam_len)) < 1) {
1044 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, feat_name[-i], &feat_name[-i]);
1045 return -1;
1046 }
1047
1048 module = lys_get_import_module(lys_node_module(node), NULL, 0, mod_name, mod_name_len);
1049 if (!module) {
1050 /* identity refers unknown data model */
1051 LOGVAL(LYE_INMOD_LEN, LY_VLOG_NONE, NULL, mod_name_len, mod_name);
1052 return -1;
1053 }
1054
Radek Krejci9ff0a922016-07-14 13:08:05 +02001055 if (module != node->module && module == lys_node_module(node)) {
1056 /* first, try to search directly in submodule where the feature was mentioned */
1057 for (j = 0; j < node->module->features_size; j++) {
1058 if (!strncmp(name, node->module->features[j].name, nam_len) && !node->module->features[j].name[nam_len]) {
1059 /* check status */
1060 if (lyp_check_status(node->flags, lys_node_module(node), node->name, node->module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001061 node->module->features[j].module, node->module->features[j].name, NULL)) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001062 return -1;
1063 }
1064 *feature = &node->module->features[j];
1065 return 0;
1066 }
1067 }
1068 }
1069
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001070 /* search in the identified module ... */
1071 for (j = 0; j < module->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001072 if (!strncmp(name, module->features[j].name, nam_len) && !module->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001073 /* check status */
1074 if (lyp_check_status(node->flags, lys_node_module(node), node->name, module->features[j].flags,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001075 module->features[j].module, module->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001076 return -1;
1077 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001078 *feature = &module->features[j];
1079 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001080 }
1081 }
1082 /* ... and all its submodules */
1083 for (i = 0; i < module->inc_size; i++) {
1084 if (!module->inc[i].submodule) {
1085 /* not yet resolved */
1086 continue;
1087 }
1088 for (j = 0; j < module->inc[i].submodule->features_size; j++) {
Michal Vasko3def8672016-07-01 11:43:09 +02001089 if (!strncmp(name, module->inc[i].submodule->features[j].name, nam_len)
1090 && !module->inc[i].submodule->features[j].name[nam_len]) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001091 /* check status */
1092 if (lyp_check_status(node->flags, lys_node_module(node), node->name,
1093 module->inc[i].submodule->features[j].flags,
1094 module->inc[i].submodule->features[j].module,
Pavol Vicanfdab9f92016-09-07 15:23:27 +02001095 module->inc[i].submodule->features[j].name, NULL)) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001096 return -1;
1097 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001098 *feature = &module->inc[i].submodule->features[j];
1099 return 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001100 }
1101 }
1102 }
1103
1104 /* not found */
1105 str = strndup(feat_name, len);
1106 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, "feature", str);
1107 free(str);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001108 return 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001109}
1110
Radek Krejci9ff0a922016-07-14 13:08:05 +02001111/*
1112 * @return
Radek Krejci69b8d922016-07-27 13:13:41 +02001113 * - 1 if enabled
1114 * - 0 if disabled
Radek Krejci9ff0a922016-07-14 13:08:05 +02001115 * - -1 if not usable by its if-feature expression
1116 */
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001117static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001118resolve_feature_value(const struct lys_feature *feat)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001119{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001120 int i;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001121
Radek Krejci9ff0a922016-07-14 13:08:05 +02001122 for (i = 0; i < feat->iffeature_size; i++) {
Radek Krejci69b8d922016-07-27 13:13:41 +02001123 if (!resolve_iffeature(&feat->iffeature[i])) {
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001124 return -1;
1125 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001126 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001127
Radek Krejci69b8d922016-07-27 13:13:41 +02001128 return feat->flags & LYS_FENABLED ? 1 : 0;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001129}
1130
1131static int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001132resolve_iffeature_recursive(struct lys_iffeature *expr, int *index_e, int *index_f)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001133{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001134 uint8_t op;
1135 int rc, a, b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001136
Radek Krejci9ff0a922016-07-14 13:08:05 +02001137 op = iff_getop(expr->expr, *index_e);
1138 (*index_e)++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001139
Radek Krejci9ff0a922016-07-14 13:08:05 +02001140 switch (op) {
1141 case LYS_IFF_F:
1142 /* resolve feature */
1143 return resolve_feature_value(expr->features[(*index_f)++]);
1144 case LYS_IFF_NOT:
1145 rc = resolve_iffeature_recursive(expr, index_e, index_f);
1146 if (rc == -1) {
1147 /* one of the referenced feature is hidden by its if-feature,
1148 * so this if-feature expression is always false */
1149 return -1;
1150 } else {
1151 /* invert result */
1152 return rc ? 0 : 1;
1153 }
1154 case LYS_IFF_AND:
1155 case LYS_IFF_OR:
1156 a = resolve_iffeature_recursive(expr, index_e, index_f);
1157 b = resolve_iffeature_recursive(expr, index_e, index_f);
1158 if (a == -1 || b == -1) {
1159 /* one of the referenced feature is hidden by its if-feature,
1160 * so this if-feature expression is always false */
1161 return -1;
1162 } else if (op == LYS_IFF_AND) {
1163 return a && b;
1164 } else { /* LYS_IFF_OR */
1165 return a || b;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001166 }
1167 }
1168
Radek Krejci9ff0a922016-07-14 13:08:05 +02001169 return -1;
1170}
1171
1172int
1173resolve_iffeature(struct lys_iffeature *expr)
1174{
1175 int rc = -1;
1176 int index_e = 0, index_f = 0;
1177
1178 if (expr->expr) {
1179 rc = resolve_iffeature_recursive(expr, &index_e, &index_f);
1180 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001181 return (rc == 1) ? 1 : 0;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001182}
1183
1184struct iff_stack {
1185 int size;
1186 int index; /* first empty item */
1187 uint8_t *stack;
1188};
1189
1190static int
1191iff_stack_push(struct iff_stack *stack, uint8_t value)
1192{
1193 if (stack->index == stack->size) {
1194 stack->size += 4;
1195 stack->stack = ly_realloc(stack->stack, stack->size * sizeof *stack->stack);
1196 if (!stack->stack) {
1197 LOGMEM;
1198 stack->size = 0;
1199 return EXIT_FAILURE;
1200 }
1201 }
1202
1203 stack->stack[stack->index++] = value;
1204 return EXIT_SUCCESS;
1205}
1206
1207static uint8_t
1208iff_stack_pop(struct iff_stack *stack)
1209{
1210 stack->index--;
1211 return stack->stack[stack->index];
1212}
1213
1214static void
1215iff_stack_clean(struct iff_stack *stack)
1216{
1217 stack->size = 0;
1218 free(stack->stack);
1219}
1220
1221static void
1222iff_setop(uint8_t *list, uint8_t op, int pos)
1223{
1224 uint8_t *item;
1225 uint8_t mask = 3;
1226
1227 assert(pos >= 0);
1228 assert(op <= 3); /* max 2 bits */
1229
1230 item = &list[pos / 4];
1231 mask = mask << 2 * (pos % 4);
1232 *item = (*item) & ~mask;
1233 *item = (*item) | (op << 2 * (pos % 4));
1234}
1235
1236uint8_t
1237iff_getop(uint8_t *list, int pos)
1238{
1239 uint8_t *item;
1240 uint8_t mask = 3, result;
1241
1242 assert(pos >= 0);
1243
1244 item = &list[pos / 4];
1245 result = (*item) & (mask << 2 * (pos % 4));
1246 return result >> 2 * (pos % 4);
1247}
1248
1249#define LYS_IFF_LP 0x04 /* ( */
1250#define LYS_IFF_RP 0x08 /* ) */
1251
Radek Krejcicbb473e2016-09-16 14:48:32 +02001252/* internal structure for passing data for UNRES_IFFEAT */
1253struct unres_iffeat_data {
1254 struct lys_node *node;
1255 const char *fname;
1256};
1257
Radek Krejci9ff0a922016-07-14 13:08:05 +02001258void
1259resolve_iffeature_getsizes(struct lys_iffeature *iffeat, unsigned int *expr_size, unsigned int *feat_size)
1260{
1261 unsigned int e = 0, f = 0, r = 0;
1262 uint8_t op;
1263
1264 assert(iffeat);
1265
1266 if (!iffeat->expr) {
1267 goto result;
1268 }
1269
1270 do {
1271 op = iff_getop(iffeat->expr, e++);
1272 switch (op) {
1273 case LYS_IFF_NOT:
1274 if (!r) {
1275 r += 1;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001276 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001277 break;
1278 case LYS_IFF_AND:
1279 case LYS_IFF_OR:
1280 if (!r) {
1281 r += 2;
1282 } else {
1283 r += 1;
1284 }
1285 break;
1286 case LYS_IFF_F:
1287 f++;
1288 if (r) {
1289 r--;
1290 }
1291 break;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001292 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001293 } while(r);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001294
Radek Krejci9ff0a922016-07-14 13:08:05 +02001295result:
1296 if (expr_size) {
1297 *expr_size = e;
1298 }
1299 if (feat_size) {
1300 *feat_size = f;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001301 }
1302}
1303
1304int
Radek Krejci9ff0a922016-07-14 13:08:05 +02001305resolve_iffeature_compile(struct lys_iffeature *iffeat_expr, const char *value, struct lys_node *node,
1306 struct unres_schema *unres)
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001307{
Radek Krejci9ff0a922016-07-14 13:08:05 +02001308 const char *c = value;
1309 int r, rc = EXIT_FAILURE;
Radek Krejci69b8d922016-07-27 13:13:41 +02001310 int i, j, last_not, checkversion = 0;
1311 unsigned int f_size = 0, expr_size = 0, f_exp = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001312 uint8_t op;
1313 struct iff_stack stack = {0, 0, NULL};
Radek Krejcicbb473e2016-09-16 14:48:32 +02001314 struct unres_iffeat_data *iff_data;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001315
Radek Krejci9ff0a922016-07-14 13:08:05 +02001316 assert(c);
1317
1318 if (isspace(c[0])) {
1319 LOGVAL(LYE_INCHAR, LY_VLOG_NONE, NULL, c[0], c);
1320 return EXIT_FAILURE;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001321 }
1322
Radek Krejci9ff0a922016-07-14 13:08:05 +02001323 /* pre-parse the expression to get sizes for arrays, also do some syntax checks of the expression */
1324 for (i = j = last_not = 0; c[i]; i++) {
1325 if (c[i] == '(') {
Radek Krejci69b8d922016-07-27 13:13:41 +02001326 checkversion = 1;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001327 j++;
1328 continue;
1329 } else if (c[i] == ')') {
1330 j--;
1331 continue;
1332 } else if (isspace(c[i])) {
1333 continue;
1334 }
1335
1336 if (!strncmp(&c[i], "not", r = 3) || !strncmp(&c[i], "and", r = 3) || !strncmp(&c[i], "or", r = 2)) {
1337 if (c[i + r] == '\0') {
Radek Krejcia98da3f2016-07-27 14:05:22 +02001338 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
Radek Krejci9ff0a922016-07-14 13:08:05 +02001339 return EXIT_FAILURE;
1340 } else if (!isspace(c[i + r])) {
1341 /* feature name starting with the not/and/or */
1342 last_not = 0;
1343 f_size++;
1344 } else if (c[i] == 'n') { /* not operation */
1345 if (last_not) {
1346 /* double not */
1347 expr_size = expr_size - 2;
1348 last_not = 0;
1349 } else {
1350 last_not = 1;
1351 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001352 } else { /* and, or */
1353 f_exp++;
Radek Krejci9ff0a922016-07-14 13:08:05 +02001354 /* not a not operation */
1355 last_not = 0;
1356 }
1357 i += r;
1358 } else {
1359 f_size++;
1360 last_not = 0;
1361 }
1362 expr_size++;
1363
1364 while (!isspace(c[i])) {
1365 if (!c[i] || c[i] == ')') {
1366 i--;
1367 break;
1368 }
1369 i++;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001370 }
1371 }
Radek Krejci69b8d922016-07-27 13:13:41 +02001372 if (j || f_exp != f_size) {
Radek Krejci9ff0a922016-07-14 13:08:05 +02001373 /* not matching count of ( and ) */
1374 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1375 return EXIT_FAILURE;
1376 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001377
Radek Krejci69b8d922016-07-27 13:13:41 +02001378 if (checkversion || expr_size > 1) {
1379 /* check that we have 1.1 module */
1380 if (node->module->version != 2) {
1381 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1382 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "YANG 1.1 if-feature expression found in 1.0 module.");
1383 return EXIT_FAILURE;
1384 }
1385 }
1386
Radek Krejci9ff0a922016-07-14 13:08:05 +02001387 /* allocate the memory */
1388 iffeat_expr->expr = calloc((j = (expr_size / 4) + ((expr_size % 4) ? 1 : 0)), sizeof *iffeat_expr->expr);
Radek Krejcicbb473e2016-09-16 14:48:32 +02001389 iffeat_expr->features = calloc(f_size, sizeof *iffeat_expr->features);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001390 stack.size = expr_size;
1391 stack.stack = malloc(expr_size * sizeof *stack.stack);
1392 if (!stack.stack || !iffeat_expr->expr || !iffeat_expr->features) {
1393 LOGMEM;
1394 goto error;
1395 }
1396 f_size--; expr_size--; /* used as indexes from now */
1397
1398 for (i--; i >= 0; i--) {
1399 if (c[i] == ')') {
1400 /* push it on stack */
1401 iff_stack_push(&stack, LYS_IFF_RP);
1402 continue;
1403 } else if (c[i] == '(') {
1404 /* pop from the stack into result all operators until ) */
1405 while((op = iff_stack_pop(&stack)) != LYS_IFF_RP) {
1406 iff_setop(iffeat_expr->expr, op, expr_size--);
1407 }
1408 continue;
1409 } else if (isspace(c[i])) {
1410 continue;
1411 }
1412
1413 /* end operator or operand -> find beginning and get what is it */
1414 j = i + 1;
1415 while (i >= 0 && !isspace(c[i]) && c[i] != '(') {
1416 i--;
1417 }
1418 i++; /* get back by one step */
1419
1420 if (!strncmp(&c[i], "not ", 4)) {
1421 if (stack.index && stack.stack[stack.index - 1] == LYS_IFF_NOT) {
1422 /* double not */
1423 iff_stack_pop(&stack);
1424 } else {
1425 /* not has the highest priority, so do not pop from the stack
1426 * as in case of AND and OR */
1427 iff_stack_push(&stack, LYS_IFF_NOT);
1428 }
1429 } else if (!strncmp(&c[i], "and ", 4)) {
1430 /* as for OR - pop from the stack all operators with the same or higher
1431 * priority and store them to the result, then push the AND to the stack */
1432 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_AND) {
1433 op = iff_stack_pop(&stack);
1434 iff_setop(iffeat_expr->expr, op, expr_size--);
1435 }
1436 iff_stack_push(&stack, LYS_IFF_AND);
1437 } else if (!strncmp(&c[i], "or ", 3)) {
1438 while (stack.index && stack.stack[stack.index - 1] <= LYS_IFF_OR) {
1439 op = iff_stack_pop(&stack);
1440 iff_setop(iffeat_expr->expr, op, expr_size--);
1441 }
1442 iff_stack_push(&stack, LYS_IFF_OR);
1443 } else {
1444 /* feature name, length is j - i */
1445
1446 /* add it to the result */
1447 iff_setop(iffeat_expr->expr, LYS_IFF_F, expr_size--);
1448
1449 /* now get the link to the feature definition. Since it can be
Radek Krejcicbb473e2016-09-16 14:48:32 +02001450 * forward referenced, we have to keep the feature name in auxiliary
1451 * structure passed into unres */
1452 iff_data = malloc(sizeof *iff_data);
1453 iff_data->node = node;
1454 iff_data->fname = lydict_insert(node->module->ctx, &c[i], j - i);
1455 r = unres_schema_add_node(node->module, unres, &iffeat_expr->features[f_size], UNRES_IFFEAT,
1456 (struct lys_node *)iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001457 f_size--;
1458
1459 if (r == -1) {
Pavol Vican4d084512016-09-29 16:38:12 +02001460 free(iff_data);
Radek Krejci9ff0a922016-07-14 13:08:05 +02001461 goto error;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001462 }
1463 }
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001464 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02001465 while (stack.index) {
1466 op = iff_stack_pop(&stack);
1467 iff_setop(iffeat_expr->expr, op, expr_size--);
1468 }
1469
1470 if (++expr_size || ++f_size) {
1471 /* not all expected operators and operands found */
1472 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, value, "if-feature");
1473 rc = EXIT_FAILURE;
1474 } else {
1475 rc = EXIT_SUCCESS;
1476 }
1477
1478error:
1479 /* cleanup */
1480 iff_stack_clean(&stack);
1481
1482 return rc;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02001483}
1484
1485/**
Michal Vasko3edeaf72016-02-11 13:17:43 +01001486 * @brief Resolve (find) a data node based on a schema-nodeid.
1487 *
1488 * Used for resolving unique statements - so id is expected to be relative and local (without reference to a different
1489 * module).
1490 *
1491 */
1492struct lyd_node *
1493resolve_data_descendant_schema_nodeid(const char *nodeid, struct lyd_node *start)
1494{
1495 char *str, *token, *p;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001496 struct lyd_node *result = NULL, *iter;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001497 const struct lys_node *schema = NULL;
Radek Krejcicc217a62016-04-08 16:58:11 +02001498 int shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001499
1500 assert(nodeid && start);
1501
1502 if (nodeid[0] == '/') {
1503 return NULL;
1504 }
1505
1506 str = p = strdup(nodeid);
1507 if (!str) {
1508 LOGMEM;
1509 return NULL;
1510 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001511
Michal Vasko3edeaf72016-02-11 13:17:43 +01001512 while (p) {
1513 token = p;
1514 p = strchr(p, '/');
1515 if (p) {
1516 *p = '\0';
1517 p++;
1518 }
1519
Radek Krejci5da4eb62016-04-08 14:45:51 +02001520 if (p) {
1521 /* inner node */
Radek Krejcicc217a62016-04-08 16:58:11 +02001522 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001523 LYS_CONTAINER | LYS_CHOICE | LYS_CASE | LYS_LEAF, 0, 0, &schema)
Radek Krejci5da4eb62016-04-08 14:45:51 +02001524 || !schema) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001525 result = NULL;
1526 break;
Radek Krejci5da4eb62016-04-08 14:45:51 +02001527 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001528
Radek Krejci5da4eb62016-04-08 14:45:51 +02001529 if (schema->nodetype & (LYS_CHOICE | LYS_CASE)) {
1530 continue;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001531 } else if (lys_parent(schema)->nodetype == LYS_CHOICE) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001532 /* shorthand case */
1533 if (!shorthand) {
1534 shorthand = 1;
Michal Vaskodcf98e62016-05-05 17:53:53 +02001535 schema = lys_parent(schema);
Radek Krejcicc217a62016-04-08 16:58:11 +02001536 continue;
1537 } else {
1538 shorthand = 0;
1539 if (schema->nodetype == LYS_LEAF) {
1540 /* should not be here, since we have leaf, which is not a shorthand nor final node */
1541 result = NULL;
1542 break;
1543 }
1544 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001545 }
1546 } else {
1547 /* final node */
Radek Krejcif3c71de2016-04-11 12:45:46 +02001548 if (resolve_descendant_schema_nodeid(token, schema ? schema->child : start->schema, LYS_LEAF,
1549 shorthand ? 0 : 1, 0, &schema)
Radek Krejcicc217a62016-04-08 16:58:11 +02001550 || !schema) {
1551 result = NULL;
1552 break;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001553 }
1554 }
Radek Krejci5da4eb62016-04-08 14:45:51 +02001555 LY_TREE_FOR(result ? result->child : start, iter) {
1556 if (iter->schema == schema) {
1557 /* move in data tree according to returned schema */
1558 result = iter;
1559 break;
1560 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001561 }
Radek Krejcicc217a62016-04-08 16:58:11 +02001562 if (!iter) {
1563 /* instance not found */
1564 result = NULL;
1565 break;
1566 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001567 }
1568 free(str);
1569
1570 return result;
1571}
1572
Radek Krejcibdf92362016-04-08 14:43:34 +02001573/*
1574 * 0 - ok (done)
1575 * 1 - continue
1576 * 2 - break
1577 * -1 - error
1578 */
1579static int
Radek Krejcicc217a62016-04-08 16:58:11 +02001580schema_nodeid_siblingcheck(const struct lys_node *sibling, int8_t *shorthand, const char *id,
Radek Krejcibdf92362016-04-08 14:43:34 +02001581 const struct lys_module *module, const char *mod_name, int mod_name_len,
Radek Krejci0fa54e92016-09-14 14:01:05 +02001582 int implemented_mod, const struct lys_node **start)
Radek Krejcibdf92362016-04-08 14:43:34 +02001583{
1584 const struct lys_module *prefix_mod;
Radek Krejcicc217a62016-04-08 16:58:11 +02001585 int sh = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001586
1587 /* module check */
1588 prefix_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001589 if (implemented_mod) {
1590 prefix_mod = lys_get_implemented_module(prefix_mod);
1591 }
Radek Krejcibdf92362016-04-08 14:43:34 +02001592 if (!prefix_mod) {
1593 return -1;
1594 }
1595 if (prefix_mod != lys_node_module(sibling)) {
1596 return 1;
1597 }
1598
1599 /* check for shorthand cases - then 'start' does not change */
Michal Vaskodcf98e62016-05-05 17:53:53 +02001600 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001601 if (*shorthand != -1) {
1602 *shorthand = *shorthand ? 0 : 1;
1603 }
1604 sh = 1;
Radek Krejcibdf92362016-04-08 14:43:34 +02001605 }
1606
1607 /* the result node? */
1608 if (!id[0]) {
Radek Krejcicc217a62016-04-08 16:58:11 +02001609 if (*shorthand == 1) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001610 return 1;
1611 }
1612 return 0;
1613 }
1614
Radek Krejcicc217a62016-04-08 16:58:11 +02001615 if (!sh) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001616 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02001617 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02001618 return -1;
1619 }
1620 *start = sibling->child;
1621 }
1622
1623 return 2;
1624}
1625
Michal Vasko3edeaf72016-02-11 13:17:43 +01001626/* start - relative, module - absolute, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1627int
1628resolve_augment_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_module *module,
1629 const struct lys_node **ret)
1630{
1631 const char *name, *mod_name, *id;
1632 const struct lys_node *sibling;
1633 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001634 int8_t shorthand = 0;
Radek Krejci0fa54e92016-09-14 14:01:05 +02001635 int implemented_search = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001636 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001637 const struct lys_module *start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001638
1639 assert(nodeid && (start || module) && !(start && module) && ret);
1640
1641 id = nodeid;
1642
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001643 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001644 return ((id - nodeid) - r) + 1;
1645 }
1646 id += r;
1647
1648 if ((is_relative && !start) || (!is_relative && !module)) {
1649 return -1;
1650 }
1651
1652 /* descendant-schema-nodeid */
1653 if (is_relative) {
Michal Vasko4c06fd82016-02-17 13:43:38 +01001654 module = start_mod = start->module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001655
1656 /* absolute-schema-nodeid */
1657 } else {
1658 start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02001659 if (start_mod != lys_main_module(module)) {
1660 /* if the submodule augments the mainmodule (or in general a module augments
1661 * itself, we don't want to search for the implemented module but augments
1662 * the module anyway. But when augmenting another module, we need the implemented
1663 * revision of the module if any */
1664 start_mod = lys_get_implemented_module(start_mod);
1665 implemented_search = 1;
1666 }
Michal Vaskoe2905632016-02-11 15:42:24 +01001667 if (!start_mod) {
1668 return -1;
1669 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001670 start = start_mod->data;
1671 }
1672
1673 while (1) {
1674 sibling = NULL;
1675 while ((sibling = lys_getnext(sibling, lys_parent(start), start_mod,
1676 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
1677 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001678 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001679 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len,
1680 implemented_search, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001681 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001682 *ret = sibling;
1683 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001684 } else if (r == 1) {
1685 continue;
1686 } else if (r == 2) {
1687 break;
1688 } else {
1689 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001690 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001691 }
1692 }
1693
1694 /* no match */
1695 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001696 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001697 return EXIT_SUCCESS;
1698 }
1699
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001700 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001701 return ((id - nodeid) - r) + 1;
1702 }
1703 id += r;
1704 }
1705
1706 /* cannot get here */
1707 LOGINT;
1708 return -1;
1709}
1710
Radek Krejcif3c71de2016-04-11 12:45:46 +02001711/* unique, refine,
1712 * >0 - unexpected char on position (ret - 1),
1713 * 0 - ok (but ret can still be NULL),
1714 * -1 - error,
1715 * -2 - violated no_innerlist */
Michal Vasko3edeaf72016-02-11 13:17:43 +01001716int
1717resolve_descendant_schema_nodeid(const char *nodeid, const struct lys_node *start, int ret_nodetype,
Radek Krejcif3c71de2016-04-11 12:45:46 +02001718 int check_shorthand, int no_innerlist, const struct lys_node **ret)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001719{
1720 const char *name, *mod_name, *id;
1721 const struct lys_node *sibling;
1722 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001723 int8_t shorthand = check_shorthand ? 0 : -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001724 /* resolved import module from the start module, it must match the next node-name-match sibling */
Radek Krejcibdf92362016-04-08 14:43:34 +02001725 const struct lys_module *module;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001726
1727 assert(nodeid && start && ret);
1728 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1729
1730 id = nodeid;
1731 module = start->module;
1732
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001733 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001734 return ((id - nodeid) - r) + 1;
1735 }
1736 id += r;
1737
1738 if (!is_relative) {
1739 return -1;
1740 }
1741
1742 while (1) {
1743 sibling = NULL;
1744 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
1745 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE))) {
1746 /* name match */
1747 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001748 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001749 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001750 if (!(sibling->nodetype & ret_nodetype)) {
1751 /* wrong node type, too bad */
1752 continue;
1753 }
1754 *ret = sibling;
1755 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001756 } else if (r == 1) {
1757 continue;
1758 } else if (r == 2) {
1759 break;
1760 } else {
1761 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001762 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001763 }
1764 }
1765
1766 /* no match */
1767 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001768 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001769 return EXIT_SUCCESS;
Radek Krejcif3c71de2016-04-11 12:45:46 +02001770 } else if (no_innerlist && sibling->nodetype == LYS_LIST) {
1771 *ret = NULL;
1772 return -2;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001773 }
1774
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001775 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001776 return ((id - nodeid) - r) + 1;
1777 }
1778 id += r;
1779 }
1780
1781 /* cannot get here */
1782 LOGINT;
1783 return -1;
1784}
1785
1786/* choice default */
1787int
1788resolve_choice_default_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node **ret)
1789{
1790 /* cannot actually be a path */
1791 if (strchr(nodeid, '/')) {
1792 return -1;
1793 }
1794
Radek Krejcif3c71de2016-04-11 12:45:46 +02001795 return resolve_descendant_schema_nodeid(nodeid, start, LYS_NO_RPC_NOTIF_NODE, 1, 0, ret);
Michal Vasko3edeaf72016-02-11 13:17:43 +01001796}
1797
1798/* uses, -1 error, EXIT_SUCCESS ok (but ret can still be NULL), >0 unexpected char on ret - 1 */
1799static int
1800resolve_uses_schema_nodeid(const char *nodeid, const struct lys_node *start, const struct lys_node_grp **ret)
1801{
1802 const struct lys_module *module;
1803 const char *mod_prefix, *name;
1804 int i, mod_prefix_len, nam_len;
1805
1806 /* parse the identifier, it must be parsed on one call */
1807 if (((i = parse_node_identifier(nodeid, &mod_prefix, &mod_prefix_len, &name, &nam_len)) < 1) || nodeid[i]) {
1808 return -i + 1;
1809 }
1810
1811 module = lys_get_import_module(start->module, mod_prefix, mod_prefix_len, NULL, 0);
1812 if (!module) {
1813 return -1;
1814 }
1815 if (module != start->module) {
1816 start = module->data;
1817 }
1818
1819 *ret = lys_find_grouping_up(name, (struct lys_node *)start);
1820
1821 return EXIT_SUCCESS;
1822}
1823
1824int
1825resolve_absolute_schema_nodeid(const char *nodeid, const struct lys_module *module, int ret_nodetype,
1826 const struct lys_node **ret)
1827{
1828 const char *name, *mod_name, *id;
1829 const struct lys_node *sibling, *start;
1830 int r, nam_len, mod_name_len, is_relative = -1;
Radek Krejcicc217a62016-04-08 16:58:11 +02001831 int8_t shorthand = 0;
Radek Krejcibdf92362016-04-08 14:43:34 +02001832 const struct lys_module *abs_start_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001833
1834 assert(nodeid && module && ret);
1835 assert(!(ret_nodetype & (LYS_USES | LYS_AUGMENT)) && ((ret_nodetype == LYS_GROUPING) || !(ret_nodetype & LYS_GROUPING)));
1836
1837 id = nodeid;
1838 start = module->data;
1839
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001840 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001841 return ((id - nodeid) - r) + 1;
1842 }
1843 id += r;
1844
1845 if (is_relative) {
1846 return -1;
1847 }
1848
1849 abs_start_mod = lys_get_import_module(module, NULL, 0, mod_name, mod_name_len);
Michal Vaskoe2905632016-02-11 15:42:24 +01001850 if (!abs_start_mod) {
1851 return -1;
1852 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001853
1854 while (1) {
1855 sibling = NULL;
1856 while ((sibling = lys_getnext(sibling, lys_parent(start), abs_start_mod, LYS_GETNEXT_WITHCHOICE
1857 | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT | LYS_GETNEXT_WITHGROUPING))) {
1858 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02001859 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Radek Krejci0fa54e92016-09-14 14:01:05 +02001860 r = schema_nodeid_siblingcheck(sibling, &shorthand, id, module, mod_name, mod_name_len, 0, &start);
Radek Krejcibdf92362016-04-08 14:43:34 +02001861 if (r == 0) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001862 if (!(sibling->nodetype & ret_nodetype)) {
1863 /* wrong node type, too bad */
1864 continue;
1865 }
1866 *ret = sibling;
1867 return EXIT_SUCCESS;
Radek Krejcibdf92362016-04-08 14:43:34 +02001868 } else if (r == 1) {
1869 continue;
1870 } else if (r == 2) {
1871 break;
1872 } else {
1873 return -1;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001874 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001875 }
1876 }
1877
1878 /* no match */
1879 if (!sibling) {
Michal Vaskoa426fef2016-03-07 10:47:31 +01001880 *ret = NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001881 return EXIT_SUCCESS;
1882 }
1883
Michal Vasko83e8e5b2016-03-11 14:29:10 +01001884 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, NULL)) < 1) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01001885 return ((id - nodeid) - r) + 1;
1886 }
1887 id += r;
1888 }
1889
1890 /* cannot get here */
1891 LOGINT;
1892 return -1;
1893}
1894
Michal Vaskoe733d682016-03-14 09:08:27 +01001895static int
Michal Vasko3547c532016-03-14 09:40:50 +01001896resolve_json_schema_list_predicate(const char *predicate, const struct lys_node_list *list, int *parsed)
Michal Vaskoe733d682016-03-14 09:08:27 +01001897{
1898 const char *name;
1899 int nam_len, has_predicate, i;
1900
Michal Vasko7b54f7e2016-05-03 15:07:31 +02001901 if (((i = parse_schema_json_predicate(predicate, &name, &nam_len, NULL, NULL, &has_predicate)) < 1)
1902 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001903 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-i], &predicate[-i]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001904 return -1;
1905 }
1906
1907 predicate += i;
1908 *parsed += i;
1909
1910 for (i = 0; i < list->keys_size; ++i) {
1911 if (!strncmp(list->keys[i]->name, name, nam_len) && !list->keys[i]->name[nam_len]) {
1912 break;
1913 }
1914 }
1915
1916 if (i == list->keys_size) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001917 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskoe733d682016-03-14 09:08:27 +01001918 return -1;
1919 }
1920
1921 /* more predicates? */
1922 if (has_predicate) {
Michal Vasko3547c532016-03-14 09:40:50 +01001923 return resolve_json_schema_list_predicate(predicate, list, parsed);
Michal Vaskoe733d682016-03-14 09:08:27 +01001924 }
1925
1926 return 0;
1927}
1928
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001929/* cannot return LYS_GROUPING, LYS_AUGMENT, LYS_USES, logs directly */
Michal Vaskoe733d682016-03-14 09:08:27 +01001930const struct lys_node *
Michal Vasko8d26e5c2016-09-08 10:03:49 +02001931resolve_json_nodeid(const char *nodeid, struct ly_ctx *ctx, const struct lys_node *start)
Michal Vasko3edeaf72016-02-11 13:17:43 +01001932{
Michal Vasko10728b52016-04-07 14:26:29 +02001933 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001934 const char *name, *mod_name, *id;
Michal Vasko3547c532016-03-14 09:40:50 +01001935 const struct lys_node *sibling;
Radek Krejcibdf92362016-04-08 14:43:34 +02001936 int r, nam_len, mod_name_len, is_relative = -1, has_predicate, shorthand = 0;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001937 /* resolved import module from the start module, it must match the next node-name-match sibling */
Michal Vaskoe733d682016-03-14 09:08:27 +01001938 const struct lys_module *prefix_mod, *module, *prev_mod;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001939
Michal Vasko3547c532016-03-14 09:40:50 +01001940 assert(nodeid && (ctx || start));
1941 if (!ctx) {
1942 ctx = start->module->ctx;
1943 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01001944
1945 id = nodeid;
1946
Michal Vaskoe733d682016-03-14 09:08:27 +01001947 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01001948 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01001949 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01001950 }
1951 id += r;
1952
1953 if (is_relative) {
Michal Vasko3547c532016-03-14 09:40:50 +01001954 assert(start);
1955 start = start->child;
1956 if (!start) {
1957 /* no descendants, fail for sure */
Michal Vasko10728b52016-04-07 14:26:29 +02001958 str = strndup(nodeid, (name + nam_len) - nodeid);
1959 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
1960 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001961 return NULL;
1962 }
1963 module = start->module;
1964 } else {
1965 if (!mod_name) {
Michal Vasko10728b52016-04-07 14:26:29 +02001966 str = strndup(nodeid, (name + nam_len) - nodeid);
1967 LOGVAL(LYE_PATH_MISSMOD, LY_VLOG_STR, nodeid);
1968 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001969 return NULL;
Michal Vasko971a3ca2016-04-01 13:09:29 +02001970 } else if (mod_name_len > LY_BUF_SIZE - 1) {
1971 LOGINT;
1972 return NULL;
Michal Vasko3547c532016-03-14 09:40:50 +01001973 }
1974
Michal Vasko971a3ca2016-04-01 13:09:29 +02001975 if (ly_buf_used && module_name[0]) {
1976 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
1977 }
1978 ly_buf_used++;
1979
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02001980 memmove(module_name, mod_name, mod_name_len);
Michal Vasko971a3ca2016-04-01 13:09:29 +02001981 module_name[mod_name_len] = '\0';
1982 module = ly_ctx_get_module(ctx, module_name, NULL);
1983
1984 if (buf_backup) {
1985 /* return previous internal buffer content */
1986 strcpy(module_name, buf_backup);
1987 free(buf_backup);
1988 buf_backup = NULL;
1989 }
1990 ly_buf_used--;
1991
Michal Vasko3547c532016-03-14 09:40:50 +01001992 if (!module) {
Michal Vasko10728b52016-04-07 14:26:29 +02001993 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
1994 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
1995 free(str);
Michal Vasko3547c532016-03-14 09:40:50 +01001996 return NULL;
1997 }
1998 start = module->data;
1999
2000 /* now it's as if there was no module name */
2001 mod_name = NULL;
2002 mod_name_len = 0;
Michal Vaskoe733d682016-03-14 09:08:27 +01002003 }
2004
Michal Vaskoe733d682016-03-14 09:08:27 +01002005 prev_mod = module;
2006
Michal Vasko3edeaf72016-02-11 13:17:43 +01002007 while (1) {
2008 sibling = NULL;
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002009 while ((sibling = lys_getnext(sibling, lys_parent(start), module,
2010 LYS_GETNEXT_WITHCHOICE | LYS_GETNEXT_WITHCASE | LYS_GETNEXT_WITHINOUT))) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002011 /* name match */
Michal Vasko0a1aaa42016-04-19 09:48:25 +02002012 if (sibling->name && !strncmp(name, sibling->name, nam_len) && !sibling->name[nam_len]) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002013 /* module check */
2014 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002015 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko8757e7c2016-03-15 10:41:30 +01002016 LOGINT;
2017 return NULL;
2018 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002019
2020 if (ly_buf_used && module_name[0]) {
2021 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2022 }
2023 ly_buf_used++;
2024
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002025 memmove(module_name, mod_name, mod_name_len);
Michal Vasko8757e7c2016-03-15 10:41:30 +01002026 module_name[mod_name_len] = '\0';
2027 /* will also find an augment module */
2028 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002029
2030 if (buf_backup) {
2031 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002032 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002033 free(buf_backup);
2034 buf_backup = NULL;
2035 }
2036 ly_buf_used--;
2037
Michal Vasko3edeaf72016-02-11 13:17:43 +01002038 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002039 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2040 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2041 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002042 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002043 }
2044 } else {
2045 prefix_mod = prev_mod;
2046 }
Michal Vasko4f0dad02016-02-15 14:08:23 +01002047 if (prefix_mod != lys_node_module(sibling)) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01002048 continue;
2049 }
2050
Michal Vaskoe733d682016-03-14 09:08:27 +01002051 /* do we have some predicates on it? */
2052 if (has_predicate) {
2053 r = 0;
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002054 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST)) {
2055 if ((r = parse_schema_json_predicate(id, NULL, NULL, NULL, NULL, &has_predicate)) < 1) {
2056 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
2057 return NULL;
2058 }
2059 } else if (sibling->nodetype == LYS_LIST) {
2060 if (resolve_json_schema_list_predicate(id, (const struct lys_node_list *)sibling, &r)) {
2061 return NULL;
2062 }
2063 } else {
Michal Vasko43c300e2016-03-22 12:54:27 +01002064 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vaskoe733d682016-03-14 09:08:27 +01002065 return NULL;
Michal Vaskoe733d682016-03-14 09:08:27 +01002066 }
2067 id += r;
2068 }
2069
Radek Krejcibdf92362016-04-08 14:43:34 +02002070 /* check for shorthand cases - then 'start' does not change */
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002071 if (lys_parent(sibling) && (lys_parent(sibling)->nodetype == LYS_CHOICE) && (sibling->nodetype != LYS_CASE)) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002072 shorthand = ~shorthand;
2073 }
2074
Michal Vasko3edeaf72016-02-11 13:17:43 +01002075 /* the result node? */
2076 if (!id[0]) {
Radek Krejcibdf92362016-04-08 14:43:34 +02002077 if (shorthand) {
2078 /* wrong path for shorthand */
Michal Vasko025e0452016-05-17 16:14:20 +02002079 str = strndup(nodeid, (name + nam_len) - nodeid);
2080 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
Michal Vasko3c0f9f52016-05-17 16:38:10 +02002081 LOGVAL(LYE_SPEC, LY_VLOG_STR, str, "Schema shorthand case path must include the virtual case statement.");
Radek Krejci9a5fccc2016-05-18 15:44:58 +02002082 free(str);
Michal Vasko025e0452016-05-17 16:14:20 +02002083 return NULL;
Radek Krejcibdf92362016-04-08 14:43:34 +02002084 }
Michal Vaskoe733d682016-03-14 09:08:27 +01002085 return sibling;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002086 }
2087
Michal Vasko8d26e5c2016-09-08 10:03:49 +02002088 if (!shorthand) {
Michal Vasko7dc71d02016-03-15 10:42:28 +01002089 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002090 if (sibling->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002091 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko7dc71d02016-03-15 10:42:28 +01002092 return NULL;
2093 }
Michal Vasko3edeaf72016-02-11 13:17:43 +01002094 start = sibling->child;
2095 }
2096
2097 /* update prev mod */
2098 prev_mod = start->module;
2099 break;
2100 }
2101 }
2102
2103 /* no match */
2104 if (!sibling) {
Michal Vasko10728b52016-04-07 14:26:29 +02002105 str = strndup(nodeid, (name + nam_len) - nodeid);
2106 LOGVAL(LYE_PATH_INNODE, LY_VLOG_STR, str);
2107 free(str);
Michal Vaskoe733d682016-03-14 09:08:27 +01002108 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002109 }
2110
Michal Vaskoe733d682016-03-14 09:08:27 +01002111 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002112 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vaskoe733d682016-03-14 09:08:27 +01002113 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002114 }
2115 id += r;
2116 }
2117
2118 /* cannot get here */
2119 LOGINT;
Michal Vaskoe733d682016-03-14 09:08:27 +01002120 return NULL;
Michal Vasko3edeaf72016-02-11 13:17:43 +01002121}
2122
Michal Vasko22448d32016-03-16 13:17:29 +01002123static int
2124resolve_partial_json_data_list_predicate(const char *predicate, const char *node_name, struct lyd_node *node, int *parsed)
2125{
2126 const char *name, *value;
2127 int nam_len, val_len, has_predicate = 1, r;
2128 uint16_t i;
Michal Vaskof29903d2016-04-18 13:13:10 +02002129 struct lyd_node_leaf_list *key;
Michal Vasko22448d32016-03-16 13:17:29 +01002130
Radek Krejci61a86c62016-03-24 11:06:44 +01002131 assert(node);
Michal Vasko22448d32016-03-16 13:17:29 +01002132 assert(node->schema->nodetype == LYS_LIST);
2133
Michal Vaskof29903d2016-04-18 13:13:10 +02002134 key = (struct lyd_node_leaf_list *)node->child;
2135 for (i = 0; i < ((struct lys_node_list *)node->schema)->keys_size; ++i) {
2136 if (!key) {
2137 /* invalid data */
2138 LOGINT;
2139 return -1;
2140 }
Michal Vasko22448d32016-03-16 13:17:29 +01002141
Michal Vasko22448d32016-03-16 13:17:29 +01002142 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002143 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, node_name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002144 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002145 }
2146
Michal Vasko7b54f7e2016-05-03 15:07:31 +02002147 if (((r = parse_schema_json_predicate(predicate, &name, &nam_len, &value, &val_len, &has_predicate)) < 1)
2148 || !strncmp(name, ".", nam_len)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002149 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, predicate[-r], &predicate[-r]);
Michal Vaskof29903d2016-04-18 13:13:10 +02002150 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002151 }
2152
2153 predicate += r;
2154 *parsed += r;
2155
Michal Vaskof29903d2016-04-18 13:13:10 +02002156 if (strncmp(key->schema->name, name, nam_len) || key->schema->name[nam_len]) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002157 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vaskof29903d2016-04-18 13:13:10 +02002158 return -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002159 }
2160
2161 /* value does not match */
Michal Vaskof29903d2016-04-18 13:13:10 +02002162 if (strncmp(key->value_str, value, val_len) || key->value_str[val_len]) {
Michal Vasko22448d32016-03-16 13:17:29 +01002163 return 1;
2164 }
Michal Vaskof29903d2016-04-18 13:13:10 +02002165
2166 key = (struct lyd_node_leaf_list *)key->next;
Michal Vasko22448d32016-03-16 13:17:29 +01002167 }
2168
2169 if (has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002170 LOGVAL(LYE_PATH_INKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko22448d32016-03-16 13:17:29 +01002171 return -1;
2172 }
2173
2174 return 0;
2175}
2176
Radek Krejci45826012016-08-24 15:07:57 +02002177/**
2178 * @brief get the closest parent of the node (or the node itself) identified by the nodeid (path)
2179 *
2180 * @param[in] nodeid Node data path to find
2181 * @param[in] llist_value If the \p nodeid identifies leaf-list, this is expected value of the leaf-list instance.
2182 * @param[in] options Bitmask of options flags, see @ref pathoptions.
2183 * @param[out] parsed Number of characters processed in \p id
2184 * @return The closes parent (or the node itself) from the path
2185 */
Michal Vasko22448d32016-03-16 13:17:29 +01002186struct lyd_node *
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002187resolve_partial_json_data_nodeid(const char *nodeid, const char *llist_value, struct lyd_node *start, int options,
2188 int *parsed)
Michal Vasko22448d32016-03-16 13:17:29 +01002189{
Michal Vasko10728b52016-04-07 14:26:29 +02002190 char *module_name = ly_buf(), *buf_backup = NULL, *str;
Michal Vasko22448d32016-03-16 13:17:29 +01002191 const char *id, *mod_name, *name;
Michal Vaskof0a50972016-10-19 11:33:55 +02002192 int r, ret, mod_name_len, nam_len, is_relative = -1, has_predicate, last_parsed, val_len;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002193 struct lyd_node *sibling, *last_match = NULL;
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002194 struct lyd_node_leaf_list *llist;
Michal Vasko22448d32016-03-16 13:17:29 +01002195 const struct lys_module *prefix_mod, *prev_mod;
2196 struct ly_ctx *ctx;
2197
2198 assert(nodeid && start && parsed);
2199
2200 ctx = start->schema->module->ctx;
2201 id = nodeid;
2202
2203 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002204 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002205 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002206 return NULL;
2207 }
2208 id += r;
2209 /* add it to parsed only after the data node was actually found */
2210 last_parsed = r;
2211
2212 if (is_relative) {
2213 prev_mod = start->schema->module;
Michal Vasko22448d32016-03-16 13:17:29 +01002214 start = start->child;
2215 } else {
2216 for (; start->parent; start = start->parent);
Michal Vasko22448d32016-03-16 13:17:29 +01002217 prev_mod = start->schema->module;
2218 }
2219
2220 while (1) {
2221 LY_TREE_FOR(start, sibling) {
Michal Vasko2411b942016-03-23 13:50:03 +01002222 /* RPC data check, return simply invalid argument, because the data tree is invalid */
2223 if (lys_parent(sibling->schema)) {
2224 if (options & LYD_PATH_OPT_OUTPUT) {
2225 if (lys_parent(sibling->schema)->nodetype == LYS_INPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002226 LOGERR(LY_EINVAL, "Provided data tree includes some RPC input nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002227 *parsed = -1;
2228 return NULL;
2229 }
2230 } else {
2231 if (lys_parent(sibling->schema)->nodetype == LYS_OUTPUT) {
Michal Vaskob7246892016-04-19 10:37:35 +02002232 LOGERR(LY_EINVAL, "Provided data tree includes some RPC output nodes (%s).", sibling->schema->name);
Michal Vasko2411b942016-03-23 13:50:03 +01002233 *parsed = -1;
2234 return NULL;
2235 }
2236 }
2237 }
2238
Michal Vasko22448d32016-03-16 13:17:29 +01002239 /* name match */
2240 if (!strncmp(name, sibling->schema->name, nam_len) && !sibling->schema->name[nam_len]) {
2241
2242 /* module check */
2243 if (mod_name) {
Michal Vasko971a3ca2016-04-01 13:09:29 +02002244 if (mod_name_len > LY_BUF_SIZE - 1) {
Michal Vasko22448d32016-03-16 13:17:29 +01002245 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002246 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002247 return NULL;
2248 }
Michal Vasko971a3ca2016-04-01 13:09:29 +02002249
2250 if (ly_buf_used && module_name[0]) {
2251 buf_backup = strndup(module_name, LY_BUF_SIZE - 1);
2252 }
2253 ly_buf_used++;
2254
Michal Vaskodf3f1ab2016-04-01 15:07:22 +02002255 memmove(module_name, mod_name, mod_name_len);
Michal Vasko22448d32016-03-16 13:17:29 +01002256 module_name[mod_name_len] = '\0';
2257 /* will also find an augment module */
2258 prefix_mod = ly_ctx_get_module(ctx, module_name, NULL);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002259
2260 if (buf_backup) {
2261 /* return previous internal buffer content */
Michal Vasko888a1292016-04-05 12:08:54 +02002262 strncpy(module_name, buf_backup, LY_BUF_SIZE - 1);
Michal Vasko971a3ca2016-04-01 13:09:29 +02002263 free(buf_backup);
2264 buf_backup = NULL;
2265 }
2266 ly_buf_used--;
2267
Michal Vasko22448d32016-03-16 13:17:29 +01002268 if (!prefix_mod) {
Michal Vasko10728b52016-04-07 14:26:29 +02002269 str = strndup(nodeid, (mod_name + mod_name_len) - nodeid);
2270 LOGVAL(LYE_PATH_INMOD, LY_VLOG_STR, str);
2271 free(str);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002272 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002273 return NULL;
2274 }
2275 } else {
2276 prefix_mod = prev_mod;
2277 }
2278 if (prefix_mod != lys_node_module(sibling->schema)) {
2279 continue;
2280 }
2281
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002282 /* leaf-list, did we find it with the correct value or not? */
Michal Vasko22448d32016-03-16 13:17:29 +01002283 if (sibling->schema->nodetype == LYS_LEAFLIST) {
Michal Vaskof0a50972016-10-19 11:33:55 +02002284 if (has_predicate) {
2285 if ((r = parse_schema_json_predicate(id, &name, &nam_len, &llist_value, &val_len, &has_predicate)) < 1) {
2286 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
2287 *parsed = -1;
2288 return NULL;
2289 }
2290 } else {
2291 r = 0;
2292 if (llist_value) {
2293 val_len = strlen(llist_value);
2294 } else {
2295 val_len = 0;
2296 }
2297 }
2298
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002299 llist = (struct lyd_node_leaf_list *)sibling;
Michal Vaskof0a50972016-10-19 11:33:55 +02002300 if ((!val_len && llist->value_str && llist->value_str[0])
2301 || (val_len && (strncmp(llist_value, llist->value_str, val_len) || llist->value_str[val_len]))) {
Michal Vasko13eb4ac2016-04-06 12:19:37 +02002302 continue;
2303 }
Michal Vaskof0a50972016-10-19 11:33:55 +02002304 id += r;
2305 last_parsed += r;
2306
Radek Krejci45826012016-08-24 15:07:57 +02002307 } else if (sibling->schema->nodetype == LYS_LIST) {
2308 /* list, we need predicates'n'stuff then */
Michal Vasko22448d32016-03-16 13:17:29 +01002309 r = 0;
2310 if (!has_predicate) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002311 LOGVAL(LYE_PATH_MISSKEY, LY_VLOG_NONE, NULL, name);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002312 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002313 return NULL;
2314 }
2315 ret = resolve_partial_json_data_list_predicate(id, name, sibling, &r);
2316 if (ret == -1) {
Michal Vasko238bd2f2016-03-23 09:39:01 +01002317 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002318 return NULL;
2319 } else if (ret == 1) {
2320 /* this list instance does not match */
2321 continue;
2322 }
2323 id += r;
2324 last_parsed += r;
2325 }
2326
2327 *parsed += last_parsed;
2328
2329 /* the result node? */
2330 if (!id[0]) {
2331 return sibling;
2332 }
2333
2334 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02002335 if (sibling->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002336 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[0], id);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002337 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002338 return NULL;
2339 }
Michal Vaskoc6c52cf2016-03-29 11:53:04 +02002340 last_match = sibling;
Michal Vasko22448d32016-03-16 13:17:29 +01002341 start = sibling->child;
2342 if (start) {
2343 prev_mod = start->schema->module;
2344 }
2345 break;
2346 }
2347 }
2348
2349 /* no match, return last match */
2350 if (!sibling) {
2351 return last_match;
2352 }
2353
2354 if ((r = parse_schema_nodeid(id, &mod_name, &mod_name_len, &name, &nam_len, &is_relative, &has_predicate)) < 1) {
Michal Vasko43c300e2016-03-22 12:54:27 +01002355 LOGVAL(LYE_PATH_INCHAR, LY_VLOG_NONE, NULL, id[-r], &id[-r]);
Michal Vasko238bd2f2016-03-23 09:39:01 +01002356 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002357 return NULL;
2358 }
2359 id += r;
2360 last_parsed = r;
2361 }
2362
2363 /* cannot get here */
2364 LOGINT;
Michal Vasko238bd2f2016-03-23 09:39:01 +01002365 *parsed = -1;
Michal Vasko22448d32016-03-16 13:17:29 +01002366 return NULL;
2367}
2368
Michal Vasko3edeaf72016-02-11 13:17:43 +01002369/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02002370 * @brief Resolves length or range intervals. Does not log.
Michal Vaskoaeb51802016-04-11 10:58:47 +02002371 * Syntax is assumed to be correct, *ret MUST be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002372 *
Michal Vaskoaeb51802016-04-11 10:58:47 +02002373 * @param[in] str_restr Restriction as a string.
2374 * @param[in] type Type of the restriction.
2375 * @param[out] ret Final interval structure that starts with
2376 * the interval of the initial type, continues with intervals
2377 * of any superior types derived from the initial one, and
2378 * finishes with intervals from our \p type.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002379 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002380 * @return EXIT_SUCCESS on succes, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002381 */
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002382int
Michal Vaskoaeb51802016-04-11 10:58:47 +02002383resolve_len_ran_interval(const char *str_restr, struct lys_type *type, struct len_ran_intv **ret)
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002384{
2385 /* 0 - unsigned, 1 - signed, 2 - floating point */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002386 int kind;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002387 int64_t local_smin, local_smax, local_fmin, local_fmax;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002388 uint64_t local_umin, local_umax;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002389 uint8_t local_fdig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002390 const char *seg_ptr, *ptr;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002391 struct len_ran_intv *local_intv = NULL, *tmp_local_intv = NULL, *tmp_intv, *intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002392
2393 switch (type->base) {
2394 case LY_TYPE_BINARY:
2395 kind = 0;
2396 local_umin = 0;
2397 local_umax = 18446744073709551615UL;
2398
2399 if (!str_restr && type->info.binary.length) {
2400 str_restr = type->info.binary.length->expr;
2401 }
2402 break;
2403 case LY_TYPE_DEC64:
2404 kind = 2;
Michal Vasko4d1f0482016-09-19 14:35:06 +02002405 local_fmin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2406 local_fmax = __INT64_C(9223372036854775807);
2407 local_fdig = type->info.dec64.dig;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002408
2409 if (!str_restr && type->info.dec64.range) {
2410 str_restr = type->info.dec64.range->expr;
2411 }
2412 break;
2413 case LY_TYPE_INT8:
2414 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002415 local_smin = __INT64_C(-128);
2416 local_smax = __INT64_C(127);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002417
2418 if (!str_restr && type->info.num.range) {
2419 str_restr = type->info.num.range->expr;
2420 }
2421 break;
2422 case LY_TYPE_INT16:
2423 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002424 local_smin = __INT64_C(-32768);
2425 local_smax = __INT64_C(32767);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002426
2427 if (!str_restr && type->info.num.range) {
2428 str_restr = type->info.num.range->expr;
2429 }
2430 break;
2431 case LY_TYPE_INT32:
2432 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002433 local_smin = __INT64_C(-2147483648);
2434 local_smax = __INT64_C(2147483647);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002435
2436 if (!str_restr && type->info.num.range) {
2437 str_restr = type->info.num.range->expr;
2438 }
2439 break;
2440 case LY_TYPE_INT64:
2441 kind = 1;
Radek Krejcif56577b2015-10-29 14:05:25 +01002442 local_smin = __INT64_C(-9223372036854775807) - __INT64_C(1);
2443 local_smax = __INT64_C(9223372036854775807);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002444
2445 if (!str_restr && type->info.num.range) {
2446 str_restr = type->info.num.range->expr;
2447 }
2448 break;
2449 case LY_TYPE_UINT8:
2450 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002451 local_umin = __UINT64_C(0);
2452 local_umax = __UINT64_C(255);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002453
2454 if (!str_restr && type->info.num.range) {
2455 str_restr = type->info.num.range->expr;
2456 }
2457 break;
2458 case LY_TYPE_UINT16:
2459 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002460 local_umin = __UINT64_C(0);
2461 local_umax = __UINT64_C(65535);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002462
2463 if (!str_restr && type->info.num.range) {
2464 str_restr = type->info.num.range->expr;
2465 }
2466 break;
2467 case LY_TYPE_UINT32:
2468 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002469 local_umin = __UINT64_C(0);
2470 local_umax = __UINT64_C(4294967295);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002471
2472 if (!str_restr && type->info.num.range) {
2473 str_restr = type->info.num.range->expr;
2474 }
2475 break;
2476 case LY_TYPE_UINT64:
2477 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002478 local_umin = __UINT64_C(0);
2479 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002480
2481 if (!str_restr && type->info.num.range) {
2482 str_restr = type->info.num.range->expr;
2483 }
2484 break;
2485 case LY_TYPE_STRING:
2486 kind = 0;
Radek Krejcif56577b2015-10-29 14:05:25 +01002487 local_umin = __UINT64_C(0);
2488 local_umax = __UINT64_C(18446744073709551615);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002489
2490 if (!str_restr && type->info.str.length) {
2491 str_restr = type->info.str.length->expr;
2492 }
2493 break;
2494 default:
2495 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002496 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002497 }
2498
2499 /* process superior types */
Michal Vaskoaeb51802016-04-11 10:58:47 +02002500 if (type->der) {
2501 if (resolve_len_ran_interval(NULL, &type->der->type, &intv)) {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002502 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002503 return -1;
Michal Vasko0c888fd2015-08-11 15:54:08 +02002504 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002505 assert(!intv || (intv->kind == kind));
2506 }
2507
2508 if (!str_restr) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002509 /* we do not have any restriction, return superior ones */
2510 *ret = intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002511 return EXIT_SUCCESS;
2512 }
2513
2514 /* adjust local min and max */
2515 if (intv) {
2516 tmp_intv = intv;
2517
2518 if (kind == 0) {
2519 local_umin = tmp_intv->value.uval.min;
2520 } else if (kind == 1) {
2521 local_smin = tmp_intv->value.sval.min;
2522 } else if (kind == 2) {
2523 local_fmin = tmp_intv->value.fval.min;
2524 }
2525
2526 while (tmp_intv->next) {
2527 tmp_intv = tmp_intv->next;
2528 }
2529
2530 if (kind == 0) {
2531 local_umax = tmp_intv->value.uval.max;
2532 } else if (kind == 1) {
2533 local_smax = tmp_intv->value.sval.max;
2534 } else if (kind == 2) {
2535 local_fmax = tmp_intv->value.fval.max;
2536 }
2537 }
2538
2539 /* finally parse our restriction */
2540 seg_ptr = str_restr;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002541 tmp_intv = NULL;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002542 while (1) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002543 if (!tmp_local_intv) {
2544 assert(!local_intv);
2545 local_intv = malloc(sizeof *local_intv);
2546 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002547 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002548 tmp_local_intv->next = malloc(sizeof *tmp_local_intv);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002549 tmp_local_intv = tmp_local_intv->next;
2550 }
Michal Vasko253035f2015-12-17 16:58:13 +01002551 if (!tmp_local_intv) {
2552 LOGMEM;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002553 goto error;
Michal Vasko253035f2015-12-17 16:58:13 +01002554 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002555
2556 tmp_local_intv->kind = kind;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002557 tmp_local_intv->type = type;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002558 tmp_local_intv->next = NULL;
2559
2560 /* min */
2561 ptr = seg_ptr;
2562 while (isspace(ptr[0])) {
2563 ++ptr;
2564 }
2565 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2566 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002567 tmp_local_intv->value.uval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002568 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002569 tmp_local_intv->value.sval.min = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002570 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002571 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.min)) {
2572 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2573 goto error;
2574 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002575 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002576 } else if (!strncmp(ptr, "min", 3)) {
2577 if (kind == 0) {
2578 tmp_local_intv->value.uval.min = local_umin;
2579 } else if (kind == 1) {
2580 tmp_local_intv->value.sval.min = local_smin;
2581 } else if (kind == 2) {
2582 tmp_local_intv->value.fval.min = local_fmin;
2583 }
2584
2585 ptr += 3;
2586 } else if (!strncmp(ptr, "max", 3)) {
2587 if (kind == 0) {
2588 tmp_local_intv->value.uval.min = local_umax;
2589 } else if (kind == 1) {
2590 tmp_local_intv->value.sval.min = local_smax;
2591 } else if (kind == 2) {
2592 tmp_local_intv->value.fval.min = local_fmax;
2593 }
2594
2595 ptr += 3;
2596 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002597 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002598 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002599 }
2600
2601 while (isspace(ptr[0])) {
2602 ptr++;
2603 }
2604
2605 /* no interval or interval */
2606 if ((ptr[0] == '|') || !ptr[0]) {
2607 if (kind == 0) {
2608 tmp_local_intv->value.uval.max = tmp_local_intv->value.uval.min;
2609 } else if (kind == 1) {
2610 tmp_local_intv->value.sval.max = tmp_local_intv->value.sval.min;
2611 } else if (kind == 2) {
2612 tmp_local_intv->value.fval.max = tmp_local_intv->value.fval.min;
2613 }
2614 } else if (!strncmp(ptr, "..", 2)) {
2615 /* skip ".." */
2616 ptr += 2;
2617 while (isspace(ptr[0])) {
2618 ++ptr;
2619 }
2620
2621 /* max */
2622 if (isdigit(ptr[0]) || (ptr[0] == '+') || (ptr[0] == '-')) {
2623 if (kind == 0) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002624 tmp_local_intv->value.uval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002625 } else if (kind == 1) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002626 tmp_local_intv->value.sval.max = strtol(ptr, (char **)&ptr, 10);
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002627 } else if (kind == 2) {
Michal Vaskod24dd012016-09-30 12:20:22 +02002628 if (parse_range_dec64(&ptr, local_fdig, &tmp_local_intv->value.fval.max)) {
2629 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, ptr, "range");
2630 goto error;
2631 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002632 }
2633 } else if (!strncmp(ptr, "max", 3)) {
2634 if (kind == 0) {
2635 tmp_local_intv->value.uval.max = local_umax;
2636 } else if (kind == 1) {
2637 tmp_local_intv->value.sval.max = local_smax;
2638 } else if (kind == 2) {
2639 tmp_local_intv->value.fval.max = local_fmax;
2640 }
2641 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002642 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002643 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002644 }
2645 } else {
Michal Vasko0c888fd2015-08-11 15:54:08 +02002646 LOGINT;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002647 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002648 }
2649
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002650 /* check min and max in correct order*/
2651 if (kind == 0) {
2652 /* current segment */
2653 if (tmp_local_intv->value.uval.min > tmp_local_intv->value.uval.max) {
2654 goto error;
2655 }
2656 if (tmp_local_intv->value.uval.min < local_umin || tmp_local_intv->value.uval.max > local_umax) {
2657 goto error;
2658 }
2659 /* segments sholud be ascending order */
Pavol Vican69f62c92016-08-30 09:06:25 +02002660 if (tmp_intv && (tmp_intv->value.uval.max >= tmp_local_intv->value.uval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002661 goto error;
2662 }
2663 } else if (kind == 1) {
2664 if (tmp_local_intv->value.sval.min > tmp_local_intv->value.sval.max) {
2665 goto error;
2666 }
2667 if (tmp_local_intv->value.sval.min < local_smin || tmp_local_intv->value.sval.max > local_smax) {
2668 goto error;
2669 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002670 if (tmp_intv && (tmp_intv->value.sval.max >= tmp_local_intv->value.sval.min)) {
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002671 goto error;
2672 }
2673 } else if (kind == 2) {
2674 if (tmp_local_intv->value.fval.min > tmp_local_intv->value.fval.max) {
2675 goto error;
2676 }
2677 if (tmp_local_intv->value.fval.min < local_fmin || tmp_local_intv->value.fval.max > local_fmax) {
2678 goto error;
2679 }
Pavol Vican69f62c92016-08-30 09:06:25 +02002680 if (tmp_intv && (tmp_intv->value.fval.max >= tmp_local_intv->value.fval.min)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002681 /* fraction-digits value is always the same (it cannot be changed in derived types) */
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002682 goto error;
2683 }
2684 }
2685
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002686 /* next segment (next OR) */
2687 seg_ptr = strchr(seg_ptr, '|');
2688 if (!seg_ptr) {
2689 break;
2690 }
2691 seg_ptr++;
Pavol Vican9e7c01d2016-08-29 09:36:17 +02002692 tmp_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002693 }
2694
2695 /* check local restrictions against superior ones */
2696 if (intv) {
2697 tmp_intv = intv;
Michal Vaskoaeb51802016-04-11 10:58:47 +02002698 tmp_local_intv = local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002699
2700 while (tmp_local_intv && tmp_intv) {
2701 /* reuse local variables */
2702 if (kind == 0) {
2703 local_umin = tmp_local_intv->value.uval.min;
2704 local_umax = tmp_local_intv->value.uval.max;
2705
2706 /* it must be in this interval */
2707 if ((local_umin >= tmp_intv->value.uval.min) && (local_umin <= tmp_intv->value.uval.max)) {
2708 /* this interval is covered, next one */
2709 if (local_umax <= tmp_intv->value.uval.max) {
2710 tmp_local_intv = tmp_local_intv->next;
2711 continue;
2712 /* ascending order of restrictions -> fail */
2713 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002714 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002715 }
2716 }
2717 } else if (kind == 1) {
2718 local_smin = tmp_local_intv->value.sval.min;
2719 local_smax = tmp_local_intv->value.sval.max;
2720
2721 if ((local_smin >= tmp_intv->value.sval.min) && (local_smin <= tmp_intv->value.sval.max)) {
2722 if (local_smax <= tmp_intv->value.sval.max) {
2723 tmp_local_intv = tmp_local_intv->next;
2724 continue;
2725 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002726 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002727 }
2728 }
2729 } else if (kind == 2) {
2730 local_fmin = tmp_local_intv->value.fval.min;
2731 local_fmax = tmp_local_intv->value.fval.max;
2732
Michal Vasko4d1f0482016-09-19 14:35:06 +02002733 if ((dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.min, local_fdig) > -1)
Pavol Vican3c8ee2b2016-09-29 13:18:13 +02002734 && (dec64cmp(local_fmin, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1)) {
Michal Vasko4d1f0482016-09-19 14:35:06 +02002735 if (dec64cmp(local_fmax, local_fdig, tmp_intv->value.fval.max, local_fdig) < 1) {
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002736 tmp_local_intv = tmp_local_intv->next;
2737 continue;
2738 } else {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002739 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002740 }
2741 }
2742 }
2743
2744 tmp_intv = tmp_intv->next;
2745 }
2746
2747 /* some interval left uncovered -> fail */
2748 if (tmp_local_intv) {
Michal Vaskoaeb51802016-04-11 10:58:47 +02002749 goto error;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002750 }
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002751 }
2752
Michal Vaskoaeb51802016-04-11 10:58:47 +02002753 /* append the local intervals to all the intervals of the superior types, return it all */
2754 if (intv) {
2755 for (tmp_intv = intv; tmp_intv->next; tmp_intv = tmp_intv->next);
2756 tmp_intv->next = local_intv;
2757 } else {
2758 intv = local_intv;
2759 }
2760 *ret = intv;
2761
2762 return EXIT_SUCCESS;
2763
2764error:
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002765 while (intv) {
2766 tmp_intv = intv->next;
2767 free(intv);
2768 intv = tmp_intv;
2769 }
Michal Vaskoaeb51802016-04-11 10:58:47 +02002770 while (local_intv) {
2771 tmp_local_intv = local_intv->next;
2772 free(local_intv);
2773 local_intv = tmp_local_intv;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002774 }
2775
Michal Vaskoaeb51802016-04-11 10:58:47 +02002776 return -1;
Michal Vaskob2daf5b2015-08-05 16:15:37 +02002777}
2778
Michal Vasko730dfdf2015-08-11 14:48:05 +02002779/**
Michal Vasko01c6fd22016-05-20 11:43:05 +02002780 * @brief Resolve a typedef, return only resolved typedefs if derived. If leafref, it must be
2781 * resolved for this function to return it. Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002782 *
2783 * @param[in] name Typedef name.
Michal Vasko1dca6882015-10-22 14:29:42 +02002784 * @param[in] mod_name Typedef name module name.
2785 * @param[in] module Main module.
2786 * @param[in] parent Parent of the resolved type definition.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002787 * @param[out] ret Pointer to the resolved typedef. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002788 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002789 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02002790 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002791int
Michal Vasko1e62a092015-12-01 12:27:20 +01002792resolve_superior_type(const char *name, const char *mod_name, const struct lys_module *module,
2793 const struct lys_node *parent, struct lys_tpdf **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002794{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002795 int i, j;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002796 struct lys_tpdf *tpdf, *match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002797 int tpdf_size;
2798
Michal Vasko1dca6882015-10-22 14:29:42 +02002799 if (!mod_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002800 /* no prefix, try built-in types */
2801 for (i = 1; i < LY_DATA_TYPE_COUNT; i++) {
2802 if (!strcmp(ly_types[i].def->name, name)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002803 if (ret) {
2804 *ret = ly_types[i].def;
2805 }
2806 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002807 }
2808 }
2809 } else {
Michal Vasko1dca6882015-10-22 14:29:42 +02002810 if (!strcmp(mod_name, module->name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002811 /* prefix refers to the current module, ignore it */
Michal Vasko1dca6882015-10-22 14:29:42 +02002812 mod_name = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002813 }
2814 }
2815
Michal Vasko1dca6882015-10-22 14:29:42 +02002816 if (!mod_name && parent) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002817 /* search in local typedefs */
2818 while (parent) {
2819 switch (parent->nodetype) {
Radek Krejci76512572015-08-04 09:47:08 +02002820 case LYS_CONTAINER:
Radek Krejcib8048692015-08-05 13:36:34 +02002821 tpdf_size = ((struct lys_node_container *)parent)->tpdf_size;
2822 tpdf = ((struct lys_node_container *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002823 break;
2824
Radek Krejci76512572015-08-04 09:47:08 +02002825 case LYS_LIST:
Radek Krejcib8048692015-08-05 13:36:34 +02002826 tpdf_size = ((struct lys_node_list *)parent)->tpdf_size;
2827 tpdf = ((struct lys_node_list *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002828 break;
2829
Radek Krejci76512572015-08-04 09:47:08 +02002830 case LYS_GROUPING:
Radek Krejcib8048692015-08-05 13:36:34 +02002831 tpdf_size = ((struct lys_node_grp *)parent)->tpdf_size;
2832 tpdf = ((struct lys_node_grp *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002833 break;
2834
Radek Krejci76512572015-08-04 09:47:08 +02002835 case LYS_RPC:
Michal Vasko44fb6382016-06-29 11:12:27 +02002836 case LYS_ACTION:
2837 tpdf_size = ((struct lys_node_rpc_action *)parent)->tpdf_size;
2838 tpdf = ((struct lys_node_rpc_action *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002839 break;
2840
Radek Krejci76512572015-08-04 09:47:08 +02002841 case LYS_NOTIF:
Radek Krejcib8048692015-08-05 13:36:34 +02002842 tpdf_size = ((struct lys_node_notif *)parent)->tpdf_size;
2843 tpdf = ((struct lys_node_notif *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002844 break;
2845
Radek Krejci76512572015-08-04 09:47:08 +02002846 case LYS_INPUT:
2847 case LYS_OUTPUT:
Michal Vasko44fb6382016-06-29 11:12:27 +02002848 tpdf_size = ((struct lys_node_inout *)parent)->tpdf_size;
2849 tpdf = ((struct lys_node_inout *)parent)->tpdf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002850 break;
2851
2852 default:
Michal Vaskodcf98e62016-05-05 17:53:53 +02002853 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002854 continue;
2855 }
2856
2857 for (i = 0; i < tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002858 if (!strcmp(tpdf[i].name, name) && tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002859 match = &tpdf[i];
2860 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002861 }
2862 }
2863
Michal Vaskodcf98e62016-05-05 17:53:53 +02002864 parent = lys_parent(parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002865 }
Radek Krejcic071c542016-01-27 14:57:51 +01002866 } else {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002867 /* get module where to search */
Michal Vaskob6729c62015-10-21 12:09:47 +02002868 module = lys_get_import_module(module, NULL, 0, mod_name, 0);
Michal Vaskoc935fff2015-08-17 14:02:06 +02002869 if (!module) {
2870 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002871 }
2872 }
2873
2874 /* search in top level typedefs */
2875 for (i = 0; i < module->tpdf_size; i++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002876 if (!strcmp(module->tpdf[i].name, name) && module->tpdf[i].type.base > 0) {
Michal Vasko01c6fd22016-05-20 11:43:05 +02002877 match = &module->tpdf[i];
2878 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002879 }
2880 }
2881
2882 /* search in submodules */
Radek Krejcic071c542016-01-27 14:57:51 +01002883 for (i = 0; i < module->inc_size && module->inc[i].submodule; i++) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002884 for (j = 0; j < module->inc[i].submodule->tpdf_size; j++) {
Radek Krejcic13db382016-08-16 10:52:42 +02002885 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 +02002886 match = &module->inc[i].submodule->tpdf[j];
2887 goto check_leafref;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002888 }
2889 }
2890 }
2891
Michal Vasko3ab70fc2015-08-17 14:06:23 +02002892 return EXIT_FAILURE;
Michal Vasko01c6fd22016-05-20 11:43:05 +02002893
2894check_leafref:
2895 if (ret) {
2896 *ret = match;
2897 }
2898 if (match->type.base == LY_TYPE_LEAFREF) {
2899 while (!match->type.info.lref.path) {
2900 match = match->type.der;
2901 assert(match);
2902 }
Michal Vasko01c6fd22016-05-20 11:43:05 +02002903 }
2904 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002905}
2906
Michal Vasko1dca6882015-10-22 14:29:42 +02002907/**
2908 * @brief Check the default \p value of the \p type. Logs directly.
2909 *
2910 * @param[in] type Type definition to use.
2911 * @param[in] value Default value to check.
Michal Vasko56826402016-03-02 11:11:37 +01002912 * @param[in] module Type module.
Michal Vasko1dca6882015-10-22 14:29:42 +02002913 *
2914 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
2915 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002916static int
Radek Krejci48464ed2016-03-17 15:44:09 +01002917check_default(struct lys_type *type, const char *value, struct lys_module *module)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02002918{
Radek Krejcibad2f172016-08-02 11:04:15 +02002919 struct lys_tpdf *base_tpdf = NULL;
Michal Vasko1dca6882015-10-22 14:29:42 +02002920 struct lyd_node_leaf_list node;
Radek Krejci37b756f2016-01-18 10:15:03 +01002921 int ret = EXIT_SUCCESS;
Michal Vasko1dca6882015-10-22 14:29:42 +02002922
Radek Krejcic13db382016-08-16 10:52:42 +02002923 if (type->base <= LY_TYPE_DER) {
Michal Vasko478c4652016-07-21 12:55:01 +02002924 /* the type was not resolved yet, nothing to do for now */
2925 return EXIT_FAILURE;
2926 }
2927
2928 if (!value) {
2929 /* we do not have a new default value, so is there any to check even, in some base type? */
2930 for (base_tpdf = type->der; base_tpdf->type.der; base_tpdf = base_tpdf->type.der) {
2931 if (base_tpdf->dflt) {
2932 value = base_tpdf->dflt;
2933 break;
2934 }
2935 }
2936
2937 if (!value) {
2938 /* no default value, nothing to check, all is well */
2939 return EXIT_SUCCESS;
2940 }
2941
2942 /* 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)? */
2943 switch (type->base) {
Michal Vasko478c4652016-07-21 12:55:01 +02002944 case LY_TYPE_IDENT:
2945 case LY_TYPE_INST:
2946 case LY_TYPE_LEAFREF:
2947 case LY_TYPE_BOOL:
2948 case LY_TYPE_EMPTY:
2949 /* these have no restrictions, so we would do the exact same work as the unres in the base typedef */
2950 return EXIT_SUCCESS;
Radek Krejcibad2f172016-08-02 11:04:15 +02002951 case LY_TYPE_BITS:
2952 /* the default value must match the restricted list of values, if the type was restricted */
2953 if (type->info.bits.count) {
2954 break;
2955 }
2956 return EXIT_SUCCESS;
2957 case LY_TYPE_ENUM:
2958 /* the default value must match the restricted list of values, if the type was restricted */
2959 if (type->info.enums.count) {
2960 break;
2961 }
2962 return EXIT_SUCCESS;
Michal Vasko478c4652016-07-21 12:55:01 +02002963 case LY_TYPE_DEC64:
2964 if (type->info.dec64.range) {
2965 break;
2966 }
2967 return EXIT_SUCCESS;
2968 case LY_TYPE_BINARY:
2969 if (type->info.binary.length) {
2970 break;
2971 }
2972 return EXIT_SUCCESS;
2973 case LY_TYPE_INT8:
2974 case LY_TYPE_INT16:
2975 case LY_TYPE_INT32:
2976 case LY_TYPE_INT64:
2977 case LY_TYPE_UINT8:
2978 case LY_TYPE_UINT16:
2979 case LY_TYPE_UINT32:
2980 case LY_TYPE_UINT64:
2981 if (type->info.num.range) {
2982 break;
2983 }
2984 return EXIT_SUCCESS;
2985 case LY_TYPE_STRING:
2986 if (type->info.str.length || type->info.str.patterns) {
2987 break;
2988 }
2989 return EXIT_SUCCESS;
2990 case LY_TYPE_UNION:
2991 /* way too much trouble learning whether we need to check the default again, so just do it */
2992 break;
2993 default:
2994 LOGINT;
2995 return -1;
2996 }
Radek Krejci55a161c2016-09-05 17:13:25 +02002997 } else if (type->base == LY_TYPE_EMPTY) {
2998 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, "default", type->parent->name);
2999 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"empty\" data type cannot have a default value.");
3000 return -1;
Michal Vasko478c4652016-07-21 12:55:01 +02003001 }
3002
Michal Vasko1dca6882015-10-22 14:29:42 +02003003 /* dummy leaf */
Radek Krejci4fe36bd2016-03-17 16:47:16 +01003004 memset(&node, 0, sizeof node);
Michal Vasko1dca6882015-10-22 14:29:42 +02003005 node.value_str = value;
3006 node.value_type = type->base;
Radek Krejci37b756f2016-01-18 10:15:03 +01003007 node.schema = calloc(1, sizeof (struct lys_node_leaf));
Michal Vasko253035f2015-12-17 16:58:13 +01003008 if (!node.schema) {
3009 LOGMEM;
3010 return -1;
3011 }
Radek Krejcibad2f172016-08-02 11:04:15 +02003012 node.schema->name = strdup("fake-default");
Michal Vasko253035f2015-12-17 16:58:13 +01003013 if (!node.schema->name) {
3014 LOGMEM;
Michal Vaskof49eda02016-07-21 12:17:01 +02003015 free(node.schema);
Michal Vasko253035f2015-12-17 16:58:13 +01003016 return -1;
3017 }
Michal Vasko56826402016-03-02 11:11:37 +01003018 node.schema->module = module;
Radek Krejci37b756f2016-01-18 10:15:03 +01003019 memcpy(&((struct lys_node_leaf *)node.schema)->type, type, sizeof *type);
Michal Vasko1dca6882015-10-22 14:29:42 +02003020
Radek Krejci37b756f2016-01-18 10:15:03 +01003021 if (type->base == LY_TYPE_LEAFREF) {
Michal Vasko1dca6882015-10-22 14:29:42 +02003022 if (!type->info.lref.target) {
3023 ret = EXIT_FAILURE;
3024 goto finish;
3025 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003026 ret = check_default(&type->info.lref.target->type, value, module);
Michal Vasko1dca6882015-10-22 14:29:42 +02003027
3028 } else if ((type->base == LY_TYPE_INST) || (type->base == LY_TYPE_IDENT)) {
3029 /* it was converted to JSON format before, nothing else sensible we can do */
3030
3031 } else {
Michal Vasko3767fb22016-07-21 12:10:57 +02003032 if (lyp_parse_value(&node, NULL, 1)) {
3033 ret = -1;
Radek Krejcibad2f172016-08-02 11:04:15 +02003034 if (base_tpdf) {
3035 /* default value was is defined in some base typedef */
3036 if ((type->base == LY_TYPE_BITS && type->der->type.der) ||
3037 (type->base == LY_TYPE_ENUM && type->der->type.der)) {
3038 /* we have refined bits/enums */
3039 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
3040 "Invalid value \"%s\" of the default statement inherited to \"%s\" from \"%s\" base type.",
3041 value, type->parent->name, base_tpdf->name);
3042 }
3043 }
Michal Vasko3767fb22016-07-21 12:10:57 +02003044 }
Michal Vasko1dca6882015-10-22 14:29:42 +02003045 }
3046
3047finish:
3048 if (node.value_type == LY_TYPE_BITS) {
3049 free(node.value.bit);
3050 }
3051 free((char *)node.schema->name);
3052 free(node.schema);
3053
3054 return ret;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003055}
3056
Michal Vasko730dfdf2015-08-11 14:48:05 +02003057/**
3058 * @brief Check a key for mandatory attributes. Logs directly.
3059 *
3060 * @param[in] key The key to check.
3061 * @param[in] flags What flags to check.
3062 * @param[in] list The list of all the keys.
3063 * @param[in] index Index of the key in the key list.
3064 * @param[in] name The name of the keys.
3065 * @param[in] len The name length.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003066 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003067 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003068 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003069static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003070check_key(struct lys_node_list *list, int index, const char *name, int len)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003071{
Radek Krejciadb57612016-02-16 13:34:34 +01003072 struct lys_node_leaf *key = list->keys[index];
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003073 char *dup = NULL;
3074 int j;
3075
3076 /* existence */
3077 if (!key) {
Michal Vaskof02e3742015-08-05 16:27:02 +02003078 if (name[len] != '\0') {
3079 dup = strdup(name);
Michal Vasko253035f2015-12-17 16:58:13 +01003080 if (!dup) {
3081 LOGMEM;
3082 return -1;
3083 }
Michal Vaskof02e3742015-08-05 16:27:02 +02003084 dup[len] = '\0';
3085 name = dup;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003086 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003087 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, list, name);
Michal Vaskoe7fc19c2015-08-05 16:24:39 +02003088 free(dup);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003089 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003090 }
3091
3092 /* uniqueness */
3093 for (j = index - 1; j >= 0; j--) {
Radek Krejciadb57612016-02-16 13:34:34 +01003094 if (key == list->keys[j]) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003095 LOGVAL(LYE_KEY_DUP, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003096 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003097 }
3098 }
3099
3100 /* key is a leaf */
Radek Krejci76512572015-08-04 09:47:08 +02003101 if (key->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003102 LOGVAL(LYE_KEY_NLEAF, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003103 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003104 }
3105
3106 /* type of the leaf is not built-in empty */
Radek Krejcic3738db2016-09-15 15:51:21 +02003107 if (key->type.base == LY_TYPE_EMPTY && key->module->version < 2) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003108 LOGVAL(LYE_KEY_TYPE, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003109 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003110 }
3111
3112 /* config attribute is the same as of the list */
Radek Krejciadb57612016-02-16 13:34:34 +01003113 if ((list->flags & LYS_CONFIG_MASK) != (key->flags & LYS_CONFIG_MASK)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003114 LOGVAL(LYE_KEY_CONFIG, LY_VLOG_LYS, list, key->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003115 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003116 }
3117
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003118 /* key is not placed from augment */
3119 if (key->parent->nodetype == LYS_AUGMENT) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003120 LOGVAL(LYE_KEY_MISS, LY_VLOG_LYS, key, key->name);
3121 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key inserted from augment.");
Radek Krejci55e2cdc2016-03-11 13:51:09 +01003122 return -1;
3123 }
3124
Radek Krejci3f21ada2016-08-01 13:34:31 +02003125 /* key is not when/if-feature -conditional */
3126 j = 0;
3127 if (key->when || (key->iffeature_size && (j = 1))) {
3128 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, key, j ? "if-feature" : "when", "leaf");
3129 LOGVAL(LYE_SPEC, LY_VLOG_LYS, key, "Key definition cannot depend on a \"%s\" condition.",
3130 j ? "if-feature" : "when");
Radek Krejci581ce772015-11-10 17:22:40 +01003131 return -1;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003132 }
3133
Michal Vasko0b85aa82016-03-07 14:37:43 +01003134 return EXIT_SUCCESS;
Michal Vasko184521f2015-09-24 13:14:26 +02003135}
Michal Vasko730dfdf2015-08-11 14:48:05 +02003136
3137/**
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003138 * @brief Resolve (test the target exists) unique. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003139 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003140 * @param[in] parent The parent node of the unique structure.
Michal Vasko0b85aa82016-03-07 14:37:43 +01003141 * @param[in] uniq_str_path One path from the unique string.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003142 *
3143 * @return EXIT_SUCCESS on succes, EXIT_FAILURE on forward reference, -1 on error.
3144 */
3145int
Radek Krejcid09d1a52016-08-11 14:05:45 +02003146resolve_unique(struct lys_node *parent, const char *uniq_str_path, uint8_t *trg_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003147{
Radek Krejci581ce772015-11-10 17:22:40 +01003148 int rc;
Michal Vasko1e62a092015-12-01 12:27:20 +01003149 const struct lys_node *leaf = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003150
Radek Krejcif3c71de2016-04-11 12:45:46 +02003151 rc = resolve_descendant_schema_nodeid(uniq_str_path, parent->child, LYS_LEAF, 1, 1, &leaf);
Michal Vasko9bb061b2016-02-12 11:00:19 +01003152 if (rc || !leaf) {
Michal Vasko0b85aa82016-03-07 14:37:43 +01003153 if (rc) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003154 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003155 if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003156 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, parent, uniq_str_path[rc - 1], &uniq_str_path[rc - 1]);
Radek Krejcif3c71de2016-04-11 12:45:46 +02003157 } else if (rc == -2) {
Michal Vaskoc66c6d82016-04-12 11:37:31 +02003158 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Unique argument references list.");
Radek Krejci581ce772015-11-10 17:22:40 +01003159 }
Michal Vasko0b85aa82016-03-07 14:37:43 +01003160 rc = -1;
Michal Vasko0b85aa82016-03-07 14:37:43 +01003161 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01003162 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3163 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target leaf not found.");
Michal Vasko0b85aa82016-03-07 14:37:43 +01003164 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003165 }
Radek Krejci581ce772015-11-10 17:22:40 +01003166 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003167 }
Michal Vasko9bb061b2016-02-12 11:00:19 +01003168 if (leaf->nodetype != LYS_LEAF) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003169 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3170 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent, "Target is not a leaf.");
Radek Krejcid09d1a52016-08-11 14:05:45 +02003171 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003172 }
3173
Radek Krejcicf509982015-12-15 09:22:44 +01003174 /* check status */
Radek Krejci48464ed2016-03-17 15:44:09 +01003175 if (lyp_check_status(parent->flags, parent->module, parent->name, leaf->flags, leaf->module, leaf->name, leaf)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003176 return -1;
3177 }
3178
Radek Krejcid09d1a52016-08-11 14:05:45 +02003179 /* check that all unique's targets are of the same config type */
3180 if (*trg_type) {
3181 if (((*trg_type == 1) && (leaf->flags & LYS_CONFIG_R)) || ((*trg_type == 2) && (leaf->flags & LYS_CONFIG_W))) {
3182 LOGVAL(LYE_INARG, LY_VLOG_LYS, parent, uniq_str_path, "unique");
3183 LOGVAL(LYE_SPEC, LY_VLOG_LYS, parent,
3184 "Leaf \"%s\" referenced in unique statement is config %s, but previous referenced leaf is config %s.",
3185 uniq_str_path, *trg_type == 1 ? "false" : "true", *trg_type == 1 ? "true" : "false");
3186 return -1;
3187 }
3188 } else {
3189 /* first unique */
3190 if (leaf->flags & LYS_CONFIG_W) {
3191 *trg_type = 1;
3192 } else {
3193 *trg_type = 2;
3194 }
3195 }
3196
Radek Krejcica7efb72016-01-18 13:06:01 +01003197 /* set leaf's unique flag */
3198 ((struct lys_node_leaf *)leaf)->flags |= LYS_UNIQUE;
3199
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003200 return EXIT_SUCCESS;
3201
3202error:
3203
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003204 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003205}
3206
Radek Krejci0c0086a2016-03-24 15:20:28 +01003207void
Michal Vasko23b61ec2015-08-19 11:19:50 +02003208unres_data_del(struct unres_data *unres, uint32_t i)
3209{
3210 /* there are items after the one deleted */
3211 if (i+1 < unres->count) {
3212 /* we only move the data, memory is left allocated, why bother */
Michal Vaskocf024702015-10-08 15:01:42 +02003213 memmove(&unres->node[i], &unres->node[i+1], (unres->count-(i+1)) * sizeof *unres->node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003214
3215 /* deleting the last item */
3216 } else if (i == 0) {
Michal Vaskocf024702015-10-08 15:01:42 +02003217 free(unres->node);
3218 unres->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003219 }
3220
3221 /* if there are no items after and it is not the last one, just move the counter */
3222 --unres->count;
3223}
3224
Michal Vasko0491ab32015-08-19 14:28:29 +02003225/**
3226 * @brief Resolve (find) a data node from a specific module. Does not log.
3227 *
3228 * @param[in] mod Module to search in.
3229 * @param[in] name Name of the data node.
3230 * @param[in] nam_len Length of the name.
3231 * @param[in] start Data node to start the search from.
3232 * @param[in,out] parents Resolved nodes. If there are some parents,
3233 * they are replaced (!!) with the resolvents.
3234 *
Michal Vasko2471e7f2016-04-11 11:00:15 +02003235 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko0491ab32015-08-19 14:28:29 +02003236 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003237static int
Michal Vasko1e62a092015-12-01 12:27:20 +01003238resolve_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 +02003239{
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003240 struct lyd_node *node;
Radek Krejcic5090c32015-08-12 09:46:19 +02003241 int flag;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003242 uint32_t i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003243
Michal Vasko23b61ec2015-08-19 11:19:50 +02003244 if (!parents->count) {
3245 parents->count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003246 parents->node = malloc(sizeof *parents->node);
Michal Vasko253035f2015-12-17 16:58:13 +01003247 if (!parents->node) {
3248 LOGMEM;
Michal Vasko2471e7f2016-04-11 11:00:15 +02003249 return -1;
Michal Vasko253035f2015-12-17 16:58:13 +01003250 }
Michal Vaskocf024702015-10-08 15:01:42 +02003251 parents->node[0] = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003252 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003253 for (i = 0; i < parents->count;) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02003254 if (parents->node[i] && (parents->node[i]->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003255 /* skip */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003256 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003257 continue;
3258 }
3259 flag = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02003260 LY_TREE_FOR(parents->node[i] ? parents->node[i]->child : start, node) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003261 if (node->schema->module == mod && !strncmp(node->schema->name, name, nam_len)
3262 && node->schema->name[nam_len] == '\0') {
3263 /* matching target */
3264 if (!flag) {
Michal Vasko9a47e122015-09-03 14:26:32 +02003265 /* put node instead of the current parent */
Michal Vaskocf024702015-10-08 15:01:42 +02003266 parents->node[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003267 flag = 1;
3268 } else {
Michal Vasko9a47e122015-09-03 14:26:32 +02003269 /* multiple matching, so create a new node */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003270 ++parents->count;
Michal Vasko253035f2015-12-17 16:58:13 +01003271 parents->node = ly_realloc(parents->node, parents->count * sizeof *parents->node);
3272 if (!parents->node) {
3273 return EXIT_FAILURE;
3274 }
Michal Vaskocf024702015-10-08 15:01:42 +02003275 parents->node[parents->count-1] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003276 ++i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003277 }
3278 }
3279 }
Radek Krejcic5090c32015-08-12 09:46:19 +02003280
3281 if (!flag) {
3282 /* remove item from the parents list */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003283 unres_data_del(parents, i);
Radek Krejcic5090c32015-08-12 09:46:19 +02003284 } else {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003285 ++i;
Radek Krejcic5090c32015-08-12 09:46:19 +02003286 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003287 }
3288
Michal Vasko0491ab32015-08-19 14:28:29 +02003289 return parents->count ? EXIT_SUCCESS : EXIT_FAILURE;
Radek Krejcic5090c32015-08-12 09:46:19 +02003290}
3291
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003292/**
3293 * @brief Resolve (find) a data node. Does not log.
3294 *
Radek Krejci581ce772015-11-10 17:22:40 +01003295 * @param[in] mod_name Module name of the data node.
3296 * @param[in] mod_name_len Length of the module name.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003297 * @param[in] name Name of the data node.
3298 * @param[in] nam_len Length of the name.
3299 * @param[in] start Data node to start the search from.
3300 * @param[in,out] parents Resolved nodes. If there are some parents,
3301 * they are replaced (!!) with the resolvents.
3302 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003303 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003304 */
Radek Krejcic5090c32015-08-12 09:46:19 +02003305static int
Radek Krejci581ce772015-11-10 17:22:40 +01003306resolve_data_node(const char *mod_name, int mod_name_len, const char *name, int name_len, struct lyd_node *start,
Michal Vasko23b61ec2015-08-19 11:19:50 +02003307 struct unres_data *parents)
Radek Krejcic5090c32015-08-12 09:46:19 +02003308{
Michal Vasko1e62a092015-12-01 12:27:20 +01003309 const struct lys_module *mod;
Michal Vasko31fc3672015-10-21 12:08:13 +02003310 char *str;
Radek Krejcic5090c32015-08-12 09:46:19 +02003311
Michal Vasko23b61ec2015-08-19 11:19:50 +02003312 assert(start);
3313
Michal Vasko31fc3672015-10-21 12:08:13 +02003314 if (mod_name) {
3315 /* we have mod_name, find appropriate module */
3316 str = strndup(mod_name, mod_name_len);
Michal Vasko253035f2015-12-17 16:58:13 +01003317 if (!str) {
3318 LOGMEM;
3319 return -1;
3320 }
Michal Vasko31fc3672015-10-21 12:08:13 +02003321 mod = ly_ctx_get_module(start->schema->module->ctx, str, NULL);
3322 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02003323 if (!mod) {
3324 /* invalid prefix */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003325 return -1;
Radek Krejcic5090c32015-08-12 09:46:19 +02003326 }
3327 } else {
3328 /* no prefix, module is the same as of current node */
3329 mod = start->schema->module;
3330 }
3331
3332 return resolve_data(mod, name, name_len, start, parents);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003333}
3334
Michal Vasko730dfdf2015-08-11 14:48:05 +02003335/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003336 * @brief Resolve a path predicate (leafref) in JSON data context. Logs directly
Radek Krejci48464ed2016-03-17 15:44:09 +01003337 * only specific errors, general no-resolvent error is left to the caller.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003338 *
Michal Vaskobb211122015-08-19 14:03:11 +02003339 * @param[in] pred Predicate to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003340 * @param[in] node Node from which the predicate is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02003341 * @param[in,out] node_match Nodes satisfying the restriction
3342 * without the predicate. Nodes not
3343 * satisfying the predicate are removed.
Michal Vasko0491ab32015-08-19 14:28:29 +02003344 * @param[out] parsed Number of characters parsed, negative on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003345 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003346 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003347 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003348static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003349resolve_path_predicate_data(const char *pred, struct lyd_node *node, struct unres_data *node_match,
Radek Krejci010e54b2016-03-15 09:40:34 +01003350 int *parsed)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003351{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003352 /* ... /node[source = destination] ... */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003353 struct unres_data source_match, dest_match;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003354 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
Michal Vasko0491ab32015-08-19 14:28:29 +02003355 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed_loc = 0, pke_parsed = 0;
3356 int has_predicate, dest_parent_times, i, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003357 uint32_t j;
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003358 struct lyd_node_leaf_list *leaf_dst, *leaf_src;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003359
3360 source_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003361 source_match.node = malloc(sizeof *source_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003362 if (!source_match.node) {
3363 LOGMEM;
3364 return -1;
3365 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003366 dest_match.count = 1;
Michal Vaskocf024702015-10-08 15:01:42 +02003367 dest_match.node = malloc(sizeof *dest_match.node);
Michal Vasko253035f2015-12-17 16:58:13 +01003368 if (!dest_match.node) {
3369 LOGMEM;
3370 return -1;
3371 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003372
3373 do {
3374 if ((i = parse_path_predicate(pred, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
3375 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003376 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, pred[-i], &pred[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003377 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003378 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003379 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003380 parsed_loc += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003381 pred += i;
3382
Michal Vasko23b61ec2015-08-19 11:19:50 +02003383 for (j = 0; j < node_match->count;) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003384 /* source */
Michal Vaskocf024702015-10-08 15:01:42 +02003385 source_match.node[0] = node_match->node[j];
Michal Vasko23b61ec2015-08-19 11:19:50 +02003386
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003387 /* must be leaf (key of a list) */
Radek Krejci581ce772015-11-10 17:22:40 +01003388 if ((rc = resolve_data_node(sour_pref, sour_pref_len, source, sour_len, node_match->node[j],
Michal Vaskocf024702015-10-08 15:01:42 +02003389 &source_match)) || (source_match.count != 1) || (source_match.node[0]->schema->nodetype != LYS_LEAF)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003390 i = 0;
3391 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003392 }
3393
3394 /* destination */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003395 dest_match.node[0] = node;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003396 dest_parent_times = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003397 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3398 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003399 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003400 rc = -1;
3401 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003402 }
Michal Vasko23b61ec2015-08-19 11:19:50 +02003403 pke_parsed = i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003404 for (i = 0; i < dest_parent_times; ++i) {
Michal Vaskocf024702015-10-08 15:01:42 +02003405 dest_match.node[0] = dest_match.node[0]->parent;
3406 if (!dest_match.node[0]) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003407 i = 0;
Michal Vasko0491ab32015-08-19 14:28:29 +02003408 rc = EXIT_FAILURE;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003409 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003410 }
3411 }
3412 while (1) {
Radek Krejci581ce772015-11-10 17:22:40 +01003413 if ((rc = resolve_data_node(dest_pref, dest_pref_len, dest, dest_len, dest_match.node[0],
Michal Vasko0491ab32015-08-19 14:28:29 +02003414 &dest_match)) || (dest_match.count != 1)) {
Michal Vasko23b61ec2015-08-19 11:19:50 +02003415 i = 0;
3416 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003417 }
3418
3419 if (pke_len == pke_parsed) {
3420 break;
3421 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003422 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003423 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003424 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path_key_expr[-i], &path_key_expr[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003425 rc = -1;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003426 goto error;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003427 }
3428 pke_parsed += i;
3429 }
3430
3431 /* check match between source and destination nodes */
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003432 leaf_dst = (struct lyd_node_leaf_list *)dest_match.node[0];
3433 while (leaf_dst->value_type == LY_TYPE_LEAFREF) {
3434 leaf_dst = (struct lyd_node_leaf_list *)leaf_dst->value.leafref;
3435 }
3436 leaf_src = (struct lyd_node_leaf_list *)source_match.node[0];
3437 while (leaf_src->value_type == LY_TYPE_LEAFREF) {
3438 leaf_src = (struct lyd_node_leaf_list *)leaf_src->value.leafref;
3439 }
3440 if (leaf_src->value_type != leaf_dst->value_type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003441 goto remove_leafref;
3442 }
3443
Radek Krejci0c2fa3a2016-06-13 15:18:03 +02003444 if (!ly_strequal(leaf_src->value_str, leaf_dst->value_str, 1)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003445 goto remove_leafref;
3446 }
3447
3448 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003449 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003450 continue;
3451
3452remove_leafref:
3453 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003454 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003455 }
3456 } while (has_predicate);
3457
Michal Vaskocf024702015-10-08 15:01:42 +02003458 free(source_match.node);
3459 free(dest_match.node);
Michal Vasko0491ab32015-08-19 14:28:29 +02003460 if (parsed) {
3461 *parsed = parsed_loc;
3462 }
3463 return EXIT_SUCCESS;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003464
3465error:
3466
3467 if (source_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003468 free(source_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003469 }
3470 if (dest_match.count) {
Michal Vaskocf024702015-10-08 15:01:42 +02003471 free(dest_match.node);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003472 }
Michal Vasko0491ab32015-08-19 14:28:29 +02003473 if (parsed) {
3474 *parsed = -parsed_loc+i;
3475 }
3476 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003477}
3478
Michal Vasko730dfdf2015-08-11 14:48:05 +02003479/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003480 * @brief Resolve a path (leafref) in JSON data context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003481 *
Michal Vaskocf024702015-10-08 15:01:42 +02003482 * @param[in] node Leafref data node.
Michal Vasko23b61ec2015-08-19 11:19:50 +02003483 * @param[in] path Path of the leafref.
Radek Krejci48464ed2016-03-17 15:44:09 +01003484 * @param[out] ret Matching nodes. Expects an empty, but allocated structure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003485 *
Michal Vasko0491ab32015-08-19 14:28:29 +02003486 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 otherwise.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003487 */
Michal Vasko184521f2015-09-24 13:14:26 +02003488static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003489resolve_path_arg_data(struct lyd_node *node, const char *path, struct unres_data *ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003490{
Radek Krejci71b795b2015-08-10 16:20:39 +02003491 struct lyd_node *data = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003492 const char *prefix, *name;
Michal Vasko0491ab32015-08-19 14:28:29 +02003493 int pref_len, nam_len, has_predicate, parent_times, i, parsed, rc;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003494 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003495
Michal Vaskocf024702015-10-08 15:01:42 +02003496 assert(node && path && ret && !ret->count);
Michal Vasko23b61ec2015-08-19 11:19:50 +02003497
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003498 parent_times = 0;
Michal Vaskod9173342015-08-17 14:35:36 +02003499 parsed = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003500
3501 /* searching for nodeset */
3502 do {
3503 if ((i = parse_path_arg(path, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003504 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, path[-i], &path[-i]);
Michal Vasko0491ab32015-08-19 14:28:29 +02003505 rc = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003506 goto error;
3507 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003508 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003509 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003510
Michal Vasko23b61ec2015-08-19 11:19:50 +02003511 if (!ret->count) {
Michal Vaskobfd98e62016-09-02 09:50:05 +02003512 if (parent_times > 0) {
3513 data = node;
3514 for (i = 1; i < parent_times; ++i) {
3515 data = data->parent;
Michal Vasko253035f2015-12-17 16:58:13 +01003516 }
Michal Vaskobfd98e62016-09-02 09:50:05 +02003517 } else if (!parent_times) {
3518 data = node->child;
3519 } else {
3520 /* absolute path */
3521 for (data = node; data->parent; data = data->parent);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003522 }
3523
Michal Vaskobfd98e62016-09-02 09:50:05 +02003524 /* we may still be parsing it and the pointer is not correct yet */
3525 if (data->prev) {
3526 while (data->prev->next) {
3527 data = data->prev;
Michal Vasko8bcdf292015-08-19 14:04:43 +02003528 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003529 }
3530 }
3531
3532 /* node identifier */
Radek Krejci581ce772015-11-10 17:22:40 +01003533 if ((rc = resolve_data_node(prefix, pref_len, name, nam_len, data, ret))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003534 if (rc == -1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003535 LOGVAL(LYE_INELEM_LEN, LY_VLOG_LYD, node, nam_len, name);
Michal Vasko184521f2015-09-24 13:14:26 +02003536 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003537 goto error;
3538 }
3539
3540 if (has_predicate) {
3541 /* we have predicate, so the current results must be lists */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003542 for (j = 0; j < ret->count;) {
Michal Vaskocf024702015-10-08 15:01:42 +02003543 if (ret->node[j]->schema->nodetype == LYS_LIST &&
3544 ((struct lys_node_list *)ret->node[0]->schema)->keys) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003545 /* leafref is ok, continue check with next leafref */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003546 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003547 continue;
3548 }
3549
3550 /* does not fulfill conditions, remove leafref record */
Michal Vasko23b61ec2015-08-19 11:19:50 +02003551 unres_data_del(ret, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003552 }
Radek Krejci48464ed2016-03-17 15:44:09 +01003553 if ((rc = resolve_path_predicate_data(path, node, ret, &i))) {
Radek Krejci010e54b2016-03-15 09:40:34 +01003554 if (rc == -1) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003555 LOGVAL(LYE_NORESOLV, LY_VLOG_LYD, node, "leafref", path);
Michal Vasko184521f2015-09-24 13:14:26 +02003556 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003557 goto error;
3558 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003559 path += i;
Michal Vaskod9173342015-08-17 14:35:36 +02003560 parsed += i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003561
Michal Vasko23b61ec2015-08-19 11:19:50 +02003562 if (!ret->count) {
Michal Vasko0491ab32015-08-19 14:28:29 +02003563 rc = EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003564 goto error;
3565 }
3566 }
3567 } while (path[0] != '\0');
3568
Michal Vaskof02e3742015-08-05 16:27:02 +02003569 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003570
3571error:
3572
Michal Vaskocf024702015-10-08 15:01:42 +02003573 free(ret->node);
3574 ret->node = NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02003575 ret->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003576
Michal Vasko0491ab32015-08-19 14:28:29 +02003577 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003578}
3579
Michal Vaskoe27516a2016-10-10 17:55:31 +00003580static int
3581resolve_path_arg_schema_valid_dep_flag(const struct lys_node *op_node, const struct lys_node *first_node, int abs_path)
3582{
3583 int dep1, dep2;
3584 const struct lys_node *node;
3585
3586 if (lys_parent(op_node)) {
3587 /* inner operation (notif/action) */
3588 if (abs_path) {
3589 return 1;
3590 } else {
3591 /* compare depth of both nodes */
3592 for (dep1 = 0, node = op_node; lys_parent(node); node = lys_parent(node));
3593 for (dep2 = 0, node = first_node; lys_parent(node); node = lys_parent(node));
3594 if ((dep2 > dep1) || ((dep2 == dep1) && (op_node != first_node))) {
3595 return 1;
3596 }
3597 }
3598 } else {
3599 /* top-level operation (notif/rpc) */
3600 if (op_node != first_node) {
3601 return 1;
3602 }
3603 }
3604
3605 return 0;
3606}
3607
Michal Vasko730dfdf2015-08-11 14:48:05 +02003608/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003609 * @brief Resolve a path (leafref) predicate in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003610 *
Michal Vaskobb211122015-08-19 14:03:11 +02003611 * @param[in] path Path to use.
Radek Krejciadb57612016-02-16 13:34:34 +01003612 * @param[in] context_node Predicate context node (where the predicate is placed).
3613 * @param[in] parent Path context node (where the path begins/is placed).
Michal Vaskoe27516a2016-10-10 17:55:31 +00003614 * @param[in] op_node Optional node if the leafref is in an operation (action/rpc/notif).
Michal Vasko730dfdf2015-08-11 14:48:05 +02003615 *
Michal Vasko184521f2015-09-24 13:14:26 +02003616 * @return 0 on forward reference, otherwise the number
3617 * of characters successfully parsed,
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003618 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003619 */
Michal Vasko1f76a282015-08-04 16:16:53 +02003620static int
Radek Krejciadb57612016-02-16 13:34:34 +01003621resolve_path_predicate_schema(const char *path, const struct lys_node *context_node,
Michal Vaskoe27516a2016-10-10 17:55:31 +00003622 struct lys_node *parent, const struct lys_node *op_node)
Michal Vasko1f76a282015-08-04 16:16:53 +02003623{
Michal Vasko1e62a092015-12-01 12:27:20 +01003624 const struct lys_node *src_node, *dst_node;
Michal Vasko1f76a282015-08-04 16:16:53 +02003625 const char *path_key_expr, *source, *sour_pref, *dest, *dest_pref;
3626 int pke_len, sour_len, sour_pref_len, dest_len, dest_pref_len, parsed = 0, pke_parsed = 0;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003627 int has_predicate, dest_parent_times = 0, i, rc, first_iter;
Michal Vasko1f76a282015-08-04 16:16:53 +02003628
3629 do {
Michal Vasko730dfdf2015-08-11 14:48:05 +02003630 if ((i = parse_path_predicate(path, &sour_pref, &sour_pref_len, &source, &sour_len, &path_key_expr,
Michal Vasko1f76a282015-08-04 16:16:53 +02003631 &pke_len, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003632 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, path[-i], path-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003633 return -parsed+i;
3634 }
3635 parsed += i;
Michal Vasko730dfdf2015-08-11 14:48:05 +02003636 path += i;
Michal Vasko1f76a282015-08-04 16:16:53 +02003637
Michal Vasko58090902015-08-13 14:04:15 +02003638 /* source (must be leaf) */
Michal Vasko36cbaa42015-12-14 13:15:48 +01003639 if (!sour_pref) {
Radek Krejciadb57612016-02-16 13:34:34 +01003640 sour_pref = context_node->module->name;
Michal Vasko36cbaa42015-12-14 13:15:48 +01003641 }
Radek Krejciadb57612016-02-16 13:34:34 +01003642 rc = lys_get_sibling(context_node->child, sour_pref, sour_pref_len, source, sour_len,
Michal Vasko59ad4582016-09-16 13:15:41 +02003643 LYS_LEAF | LYS_LEAFLIST | LYS_AUGMENT, &src_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003644 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003645 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko184521f2015-09-24 13:14:26 +02003646 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003647 }
3648
3649 /* destination */
3650 if ((i = parse_path_key_expr(path_key_expr, &dest_pref, &dest_pref_len, &dest, &dest_len,
3651 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003652 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 +02003653 return -parsed;
3654 }
3655 pke_parsed += i;
3656
Radek Krejciadb57612016-02-16 13:34:34 +01003657 for (i = 0, dst_node = parent; i < dest_parent_times; ++i) {
Michal Vaskofbaead72016-10-07 10:54:48 +02003658 /* path is supposed to be evaluated in data tree, so we have to skip
3659 * all schema nodes that cannot be instantiated in data tree */
3660 for (dst_node = lys_parent(dst_node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003661 dst_node && !(dst_node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Michal Vaskofbaead72016-10-07 10:54:48 +02003662 dst_node = lys_parent(dst_node));
3663
Michal Vasko1f76a282015-08-04 16:16:53 +02003664 if (!dst_node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003665 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003666 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003667 }
3668 }
Michal Vaskoe27516a2016-10-10 17:55:31 +00003669 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003670 while (1) {
Michal Vasko36cbaa42015-12-14 13:15:48 +01003671 if (!dest_pref) {
3672 dest_pref = dst_node->module->name;
3673 }
3674 rc = lys_get_sibling(dst_node->child, dest_pref, dest_pref_len, dest, dest_len,
Michal Vasko165dc4a2015-10-23 09:44:27 +02003675 LYS_CONTAINER | LYS_LIST | LYS_LEAF | LYS_AUGMENT, &dst_node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003676 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003677 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path_key_expr);
Michal Vasko184521f2015-09-24 13:14:26 +02003678 return 0;
Michal Vasko1f76a282015-08-04 16:16:53 +02003679 }
3680
Michal Vaskoe27516a2016-10-10 17:55:31 +00003681 if (first_iter) {
3682 if (resolve_path_arg_schema_valid_dep_flag(op_node, dst_node, 0)) {
3683 parent->flags |= LYS_VALID_DEP;
3684 }
3685 first_iter = 0;
3686 }
3687
Michal Vasko1f76a282015-08-04 16:16:53 +02003688 if (pke_len == pke_parsed) {
3689 break;
3690 }
3691
3692 if ((i = parse_path_key_expr(path_key_expr+pke_parsed, &dest_pref, &dest_pref_len, &dest, &dest_len,
3693 &dest_parent_times)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003694 LOGVAL(LYE_INCHAR, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent,
Radek Krejciadb57612016-02-16 13:34:34 +01003695 (path_key_expr+pke_parsed)[-i], (path_key_expr+pke_parsed)-i);
Michal Vasko1f76a282015-08-04 16:16:53 +02003696 return -parsed;
3697 }
3698 pke_parsed += i;
3699 }
3700
3701 /* check source - dest match */
Michal Vasko59ad4582016-09-16 13:15:41 +02003702 if (dst_node->nodetype != src_node->nodetype) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003703 LOGVAL(LYE_NORESOLV, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "leafref predicate", path-parsed);
Michal Vasko59ad4582016-09-16 13:15:41 +02003704 LOGVAL(LYE_SPEC, parent ? LY_VLOG_LYS : LY_VLOG_NONE, parent, "Destination node is not a %s, but a %s.",
3705 strnodetype(src_node->nodetype), strnodetype(dst_node->nodetype));
Michal Vasko184521f2015-09-24 13:14:26 +02003706 return -parsed;
3707 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003708 } while (has_predicate);
3709
3710 return parsed;
3711}
3712
Michal Vasko730dfdf2015-08-11 14:48:05 +02003713/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003714 * @brief Resolve a path (leafref) in JSON schema context. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003715 *
Michal Vaskobb211122015-08-19 14:03:11 +02003716 * @param[in] path Path to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003717 * @param[in] parent_node Parent of the leafref.
Radek Krejci2f12f852016-01-08 12:59:57 +01003718 * @param[in] parent_tpdf Flag if the parent node is actually typedef, in that case the path
3719 * has to contain absolute path
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003720 * @param[out] ret Pointer to the resolved schema node. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003721 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003722 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003723 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003724static int
Radek Krejci48464ed2016-03-17 15:44:09 +01003725resolve_path_arg_schema(const char *path, struct lys_node *parent, int parent_tpdf,
Michal Vasko36cbaa42015-12-14 13:15:48 +01003726 const struct lys_node **ret)
Michal Vasko1f76a282015-08-04 16:16:53 +02003727{
Michal Vaskoe27516a2016-10-10 17:55:31 +00003728 const struct lys_node *node, *op_node = NULL;
Radek Krejci27fe55e2016-09-13 17:13:35 +02003729 const struct lys_module *mod, *mod2;
Michal Vasko1f76a282015-08-04 16:16:53 +02003730 const char *id, *prefix, *name;
3731 int pref_len, nam_len, parent_times, has_predicate;
Michal Vaskoe27516a2016-10-10 17:55:31 +00003732 int i, first_iter, rc;
Michal Vasko1f76a282015-08-04 16:16:53 +02003733
Michal Vasko184521f2015-09-24 13:14:26 +02003734 first_iter = 1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003735 parent_times = 0;
3736 id = path;
3737
Michal Vaskoe27516a2016-10-10 17:55:31 +00003738 /* find operation schema we are in, if applicable */
Michal Vaskoe9914d12016-10-07 14:32:37 +02003739 if (!parent_tpdf) {
Michal Vaskoe27516a2016-10-10 17:55:31 +00003740 for (op_node = lys_parent(parent);
3741 op_node && !(op_node->nodetype & (LYS_ACTION | LYS_NOTIF | LYS_RPC));
3742 op_node = lys_parent(op_node));
Michal Vaskoe9914d12016-10-07 14:32:37 +02003743 }
3744
Radek Krejci27fe55e2016-09-13 17:13:35 +02003745 mod2 = lys_node_module(parent);
Michal Vasko1f76a282015-08-04 16:16:53 +02003746 do {
3747 if ((i = parse_path_arg(id, &prefix, &pref_len, &name, &nam_len, &parent_times, &has_predicate)) < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01003748 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, id[-i], &id[-i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003749 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003750 }
3751 id += i;
3752
Michal Vasko184521f2015-09-24 13:14:26 +02003753 if (first_iter) {
Michal Vasko1f76a282015-08-04 16:16:53 +02003754 if (parent_times == -1) {
Radek Krejcic071c542016-01-27 14:57:51 +01003755 /* resolve prefix of the module */
Radek Krejciadb57612016-02-16 13:34:34 +01003756 mod = lys_get_import_module(parent->module, NULL, 0, prefix, pref_len);
Radek Krejci0fa54e92016-09-14 14:01:05 +02003757 mod = lys_get_implemented_module(mod);
Radek Krejcic071c542016-01-27 14:57:51 +01003758 /* get start node */
3759 node = mod ? mod->data : NULL;
Michal Vasko58090902015-08-13 14:04:15 +02003760 if (!node) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003761 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3762 "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003763 return EXIT_FAILURE;
Michal Vasko58090902015-08-13 14:04:15 +02003764 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003765 } else if (parent_times > 0) {
Radek Krejci2f12f852016-01-08 12:59:57 +01003766 if (parent_tpdf) {
3767 /* the path is not allowed to contain relative path since we are in top level typedef */
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003768 LOGVAL(LYE_NORESOLV, 0, NULL, "leafref", path);
Radek Krejci2f12f852016-01-08 12:59:57 +01003769 return -1;
3770 }
3771
Michal Vasko94458082016-10-07 14:34:36 +02003772 /* we are looking for a sibling of a node, node it's parent (that is why parent_times - 1) */
3773 for (i = 0, node = parent; i < parent_times - 1; i++) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02003774 /* path is supposed to be evaluated in data tree, so we have to skip
3775 * all schema nodes that cannot be instantiated in data tree */
3776 for (node = lys_parent(node);
Michal Vaskoe27516a2016-10-10 17:55:31 +00003777 node && !(node->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_ACTION | LYS_NOTIF | LYS_RPC));
Radek Krejci3a5501d2016-07-18 22:03:34 +02003778 node = lys_parent(node));
3779
Michal Vasko1f76a282015-08-04 16:16:53 +02003780 if (!node) {
Michal Vaskoe9914d12016-10-07 14:32:37 +02003781 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003782 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003783 }
3784 }
Michal Vaskoe01eca52015-08-13 14:42:02 +02003785 } else {
3786 LOGINT;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003787 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003788 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003789 } else {
Michal Vasko7dc71d02016-03-15 10:42:28 +01003790 /* move down the tree, if possible */
Radek Krejcibf2abff2016-08-23 15:51:52 +02003791 if (node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
Michal Vasko2f5aceb2016-03-22 10:24:14 +01003792 LOGVAL(LYE_INCHAR, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, name[0], name);
Michal Vasko7dc71d02016-03-15 10:42:28 +01003793 return -1;
3794 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003795 node = node->child;
Radek Krejci43ccc4c2016-10-18 20:40:06 +02003796 if (!node) {
3797 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3798 "leafref", path);
3799 return EXIT_FAILURE;
3800 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003801 }
3802
Michal Vasko4f0dad02016-02-15 14:08:23 +01003803 if (!prefix) {
Radek Krejciadb57612016-02-16 13:34:34 +01003804 prefix = lys_node_module(parent)->name;
Michal Vasko4f0dad02016-02-15 14:08:23 +01003805 }
3806
Michal Vasko36cbaa42015-12-14 13:15:48 +01003807 rc = lys_get_sibling(node, prefix, pref_len, name, nam_len, LYS_ANY & ~(LYS_USES | LYS_GROUPING), &node);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003808 if (rc) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003809 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko7a55bea2016-05-02 14:51:20 +02003810 return EXIT_FAILURE;
Michal Vasko1f76a282015-08-04 16:16:53 +02003811 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003812
Michal Vaskoe27516a2016-10-10 17:55:31 +00003813 if (first_iter) {
3814 /* set external dependency flag, we can decide based on the first found node */
3815 if (!parent_tpdf && op_node && parent_times &&
3816 resolve_path_arg_schema_valid_dep_flag(op_node, node, (parent_times == -1 ? 1 : 0))) {
3817 parent->flags |= LYS_VALID_DEP;
3818 }
3819 first_iter = 0;
3820 }
3821
Michal Vasko1f76a282015-08-04 16:16:53 +02003822 if (has_predicate) {
3823 /* we have predicate, so the current result must be list */
3824 if (node->nodetype != LYS_LIST) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003825 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003826 return -1;
Michal Vasko1f76a282015-08-04 16:16:53 +02003827 }
3828
Michal Vaskoe27516a2016-10-10 17:55:31 +00003829 i = resolve_path_predicate_schema(id, node, parent, op_node);
Radek Krejci27fe55e2016-09-13 17:13:35 +02003830 if (i <= 0) {
3831 if (i == 0) {
3832 return EXIT_FAILURE;
3833 } else { /* i < 0 */
3834 return -1;
3835 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003836 }
3837 id += i;
3838 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003839 mod = lys_node_module(node);
3840 if (!mod->implemented && mod != mod2) {
3841 /* set the module implemented */
3842 if (lys_set_implemented(mod)) {
3843 return -1;
3844 }
3845 }
Michal Vasko1f76a282015-08-04 16:16:53 +02003846 } while (id[0]);
3847
Michal Vaskoca917682016-07-25 11:00:37 +02003848 /* the target must be leaf or leaf-list (in YANG 1.1 only) */
3849 if ((node->nodetype != LYS_LEAF) && ((lys_node_module(parent)->version != 2) || (node->nodetype != LYS_LEAFLIST))) {
Michal Vasko3e9f41e2016-05-20 11:41:39 +02003850 LOGVAL(LYE_NORESOLV, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent, "leafref", path);
Radek Krejcid47daf62016-08-22 16:23:38 +02003851 LOGVAL(LYE_SPEC, parent_tpdf ? LY_VLOG_NONE : LY_VLOG_LYS, parent_tpdf ? NULL : parent,
3852 "Leafref target \"%s\" is not a leaf%s.", path,
3853 lys_node_module(parent)->version != 2 ? "" : " nor a leaf-list");
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003854 return -1;
Radek Krejcib1c12512015-08-11 11:22:04 +02003855 }
3856
Radek Krejcicf509982015-12-15 09:22:44 +01003857 /* check status */
Radek Krejciadb57612016-02-16 13:34:34 +01003858 if (lyp_check_status(parent->flags, parent->module, parent->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01003859 node->flags, node->module, node->name, node)) {
Radek Krejcicf509982015-12-15 09:22:44 +01003860 return -1;
3861 }
3862
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003863 if (ret) {
3864 *ret = node;
3865 }
Radek Krejci27fe55e2016-09-13 17:13:35 +02003866
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003867 return EXIT_SUCCESS;
Michal Vasko1f76a282015-08-04 16:16:53 +02003868}
3869
Michal Vasko730dfdf2015-08-11 14:48:05 +02003870/**
Michal Vaskof39142b2015-10-21 11:40:05 +02003871 * @brief Resolve instance-identifier predicate in JSON data format.
3872 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003873 *
Michal Vaskobb211122015-08-19 14:03:11 +02003874 * @param[in] pred Predicate to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003875 * @param[in,out] node_match Nodes matching the restriction without
3876 * the predicate. Nodes not satisfying
3877 * the predicate are removed.
3878 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02003879 * @return Number of characters successfully parsed,
3880 * positive on success, negative on failure.
Michal Vasko730dfdf2015-08-11 14:48:05 +02003881 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003882static int
Michal Vaskof39142b2015-10-21 11:40:05 +02003883resolve_predicate(const char *pred, struct unres_data *node_match)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003884{
Michal Vasko730dfdf2015-08-11 14:48:05 +02003885 /* ... /node[target = value] ... */
Michal Vaskob2f40be2016-09-08 16:03:48 +02003886 struct lyd_node *target;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003887 const char *model, *name, *value;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003888 int mod_len, nam_len, val_len, i, has_predicate, cur_idx, idx, parsed, pred_iter, k;
Michal Vasko1f2cc332015-08-19 11:18:32 +02003889 uint32_t j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003890
Michal Vasko1f2cc332015-08-19 11:18:32 +02003891 assert(pred && node_match->count);
3892
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003893 idx = -1;
3894 parsed = 0;
3895
Michal Vaskob2f40be2016-09-08 16:03:48 +02003896 pred_iter = -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003897 do {
Michal Vaskof39142b2015-10-21 11:40:05 +02003898 if ((i = parse_predicate(pred, &model, &mod_len, &name, &nam_len, &value, &val_len, &has_predicate)) < 1) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003899 return -parsed+i;
3900 }
3901 parsed += i;
3902 pred += i;
3903
3904 if (isdigit(name[0])) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003905 /* pos */
3906 assert(!value);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003907 idx = atoi(name);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003908 } else if (name[0] != '.') {
3909 /* list keys */
3910 if (pred_iter < 0) {
3911 pred_iter = 1;
3912 } else {
3913 ++pred_iter;
3914 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003915 }
3916
Michal Vaskof2f28a12016-09-09 12:43:06 +02003917 for (cur_idx = 1, j = 0; j < node_match->count; ++cur_idx) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003918 /* target */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003919 if (name[0] == '.') {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003920 /* leaf-list value */
Michal Vaskocf024702015-10-08 15:01:42 +02003921 if (node_match->node[j]->schema->nodetype != LYS_LEAFLIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003922 goto remove_instid;
3923 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003924
3925 target = node_match->node[j];
3926 /* check the value */
3927 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3928 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3929 goto remove_instid;
3930 }
3931
3932 } else if (!value) {
3933 /* keyless list position */
3934 if ((node_match->node[j]->schema->nodetype != LYS_LIST)
3935 || ((struct lys_node_list *)node_match->node[j]->schema)->keys) {
3936 goto remove_instid;
3937 }
3938
3939 if (idx != cur_idx) {
3940 goto remove_instid;
3941 }
3942
3943 } else {
3944 /* list key value */
Michal Vaskocf024702015-10-08 15:01:42 +02003945 if (node_match->node[j]->schema->nodetype != LYS_LIST) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003946 goto remove_instid;
3947 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02003948
3949 /* key module must match the list module */
3950 if (strncmp(node_match->node[j]->schema->module->name, model, mod_len)
3951 || node_match->node[j]->schema->module->name[mod_len]) {
3952 goto remove_instid;
3953 }
3954 /* find the key leaf */
Michal Vasko045182c2016-09-09 12:44:07 +02003955 for (k = 1, target = node_match->node[j]->child; target && (k < pred_iter); k++, target = target->next);
Michal Vaskob2f40be2016-09-08 16:03:48 +02003956 if (!target) {
3957 goto remove_instid;
3958 }
3959 if ((struct lys_node_leaf *)target->schema !=
3960 ((struct lys_node_list *)node_match->node[j]->schema)->keys[pred_iter - 1]) {
3961 goto remove_instid;
3962 }
3963
3964 /* check the value */
3965 if (strncmp(((struct lyd_node_leaf_list *)target)->value_str, value, val_len)
3966 || ((struct lyd_node_leaf_list *)target)->value_str[val_len]) {
3967 goto remove_instid;
3968 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003969 }
3970
Michal Vaskob2f40be2016-09-08 16:03:48 +02003971 /* instid is ok, continue check with the next one */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003972 ++j;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003973 continue;
3974
3975remove_instid:
Michal Vaskob2f40be2016-09-08 16:03:48 +02003976 /* does not fulfill conditions, remove instid record */
Michal Vasko1f2cc332015-08-19 11:18:32 +02003977 unres_data_del(node_match, j);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003978 }
3979 } while (has_predicate);
3980
Michal Vaskob2f40be2016-09-08 16:03:48 +02003981 /* check that all list keys were specified */
3982 if ((pred_iter > 0) && node_match->count) {
Michal Vasko045182c2016-09-09 12:44:07 +02003983 j = 0;
3984 while (j < node_match->count) {
Michal Vaskob2f40be2016-09-08 16:03:48 +02003985 assert(node_match->node[j]->schema->nodetype == LYS_LIST);
3986 if (pred_iter < ((struct lys_node_list *)node_match->node[j]->schema)->keys_size) {
3987 /* not enough predicates, just remove the list instance */
3988 unres_data_del(node_match, j);
Michal Vasko045182c2016-09-09 12:44:07 +02003989 } else {
3990 ++j;
Michal Vaskob2f40be2016-09-08 16:03:48 +02003991 }
3992 }
3993
3994 if (!node_match->count) {
3995 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Instance identifier is missing some list keys.");
3996 }
3997 }
3998
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02003999 return parsed;
4000}
4001
Michal Vasko730dfdf2015-08-11 14:48:05 +02004002/**
Michal Vaskof39142b2015-10-21 11:40:05 +02004003 * @brief Resolve instance-identifier in JSON data format. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004004 *
Radek Krejciadb57612016-02-16 13:34:34 +01004005 * @param[in] data Data node where the path is used
Michal Vasko730dfdf2015-08-11 14:48:05 +02004006 * @param[in] path Instance-identifier node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004007 *
Radek Krejcic5090c32015-08-12 09:46:19 +02004008 * @return Matching node or NULL if no such a node exists. If error occurs, NULL is returned and ly_errno is set.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004009 */
Michal Vasko184521f2015-09-24 13:14:26 +02004010static struct lyd_node *
Radek Krejci48464ed2016-03-17 15:44:09 +01004011resolve_instid(struct lyd_node *data, const char *path)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004012{
Radek Krejcic5090c32015-08-12 09:46:19 +02004013 int i = 0, j;
4014 struct lyd_node *result = NULL;
Michal Vaskob2f40be2016-09-08 16:03:48 +02004015 const struct lys_module *mod;
Radek Krejcic5090c32015-08-12 09:46:19 +02004016 struct ly_ctx *ctx = data->schema->module->ctx;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004017 const char *model, *name;
Radek Krejcic5090c32015-08-12 09:46:19 +02004018 char *str;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004019 int mod_len, name_len, has_predicate;
4020 struct unres_data node_match;
Michal Vasko1f2cc332015-08-19 11:18:32 +02004021
4022 memset(&node_match, 0, sizeof node_match);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004023
Radek Krejcic5090c32015-08-12 09:46:19 +02004024 /* we need root to resolve absolute path */
4025 for (; data->parent; data = data->parent);
Michal Vaskodb9323c2015-10-16 10:32:44 +02004026 /* we're still parsing it and the pointer is not correct yet */
Michal Vasko0491ab32015-08-19 14:28:29 +02004027 if (data->prev) {
4028 for (; data->prev->next; data = data->prev);
4029 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004030
Radek Krejcic5090c32015-08-12 09:46:19 +02004031 /* search for the instance node */
4032 while (path[i]) {
Michal Vaskof39142b2015-10-21 11:40:05 +02004033 j = parse_instance_identifier(&path[i], &model, &mod_len, &name, &name_len, &has_predicate);
Radek Krejcic5090c32015-08-12 09:46:19 +02004034 if (j <= 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004035 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, data, path[i-j], &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004036 goto error;
4037 }
Radek Krejcic5090c32015-08-12 09:46:19 +02004038 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004039
Michal Vaskob2f40be2016-09-08 16:03:48 +02004040 str = strndup(model, mod_len);
4041 if (!str) {
4042 LOGMEM;
4043 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004044 }
Michal Vaskob2f40be2016-09-08 16:03:48 +02004045 mod = ly_ctx_get_module(ctx, str, NULL);
4046 free(str);
Radek Krejcic5090c32015-08-12 09:46:19 +02004047
Michal Vasko1f2cc332015-08-19 11:18:32 +02004048 if (resolve_data(mod, name, name_len, data, &node_match)) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004049 /* no instance exists */
4050 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004051 }
4052
4053 if (has_predicate) {
4054 /* we have predicate, so the current results must be list or leaf-list */
Michal Vaskof39142b2015-10-21 11:40:05 +02004055 j = resolve_predicate(&path[i], &node_match);
Radek Krejcic5090c32015-08-12 09:46:19 +02004056 if (j < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004057 LOGVAL(LYE_INPRED, LY_VLOG_LYD, data, &path[i-j]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004058 goto error;
4059 }
Michal Vasko1f2cc332015-08-19 11:18:32 +02004060 i += j;
Michal Vaskob387c482015-08-12 09:32:59 +02004061
Michal Vasko1f2cc332015-08-19 11:18:32 +02004062 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004063 /* no instance exists */
4064 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004065 }
4066 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004067 }
4068
Michal Vasko1f2cc332015-08-19 11:18:32 +02004069 if (!node_match.count) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004070 /* no instance exists */
4071 return NULL;
Michal Vasko23b61ec2015-08-19 11:19:50 +02004072 } else if (node_match.count > 1) {
Radek Krejcic5090c32015-08-12 09:46:19 +02004073 /* instance identifier must resolve to a single node */
Radek Krejci48464ed2016-03-17 15:44:09 +01004074 LOGVAL(LYE_TOOMANY, LY_VLOG_LYD, data, path, "data tree");
Michal Vaskod6adbaa2016-04-11 11:01:09 +02004075 goto error;
Radek Krejcic5090c32015-08-12 09:46:19 +02004076 } else {
4077 /* we have required result, remember it and cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004078 result = node_match.node[0];
4079 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004080 return result;
4081 }
4082
4083error:
Radek Krejcic5090c32015-08-12 09:46:19 +02004084 /* cleanup */
Michal Vaskocf024702015-10-08 15:01:42 +02004085 free(node_match.node);
Radek Krejcic5090c32015-08-12 09:46:19 +02004086 return NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004087}
4088
Michal Vasko730dfdf2015-08-11 14:48:05 +02004089/**
Michal Vasko9e635ac2016-10-17 11:44:09 +02004090 * @brief Check all XPath expressions of a node (when and must), set LYS_XPATH_DEP flag if required.
4091 *
4092 * @param[in] node Node to examine.
4093 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
4094 */
4095static int
4096check_node_xpath(struct lys_node *node)
4097{
4098 struct lys_node *parent, *elem;
4099 struct lyxp_set set;
4100 uint32_t i;
4101 int rc;
4102
4103 parent = node;
4104 while (parent) {
4105 if (parent->nodetype == LYS_GROUPING) {
4106 /* unresolved grouping, skip for now (will be checked later) */
4107 return EXIT_SUCCESS;
4108 }
4109 if (parent->nodetype == LYS_AUGMENT) {
4110 if (!((struct lys_node_augment *)parent)->target) {
4111 /* uresolved augment, skip for now (will be checked later) */
4112 return EXIT_SUCCESS;
4113 } else {
4114 parent = ((struct lys_node_augment *)parent)->target;
4115 continue;
4116 }
4117 }
4118 parent = parent->parent;
4119 }
4120
4121 rc = lyxp_node_atomize(node, &set);
4122 if (rc) {
4123 return rc;
4124 }
4125
4126 for (parent = node; parent && !(parent->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF)); parent = lys_parent(parent));
4127
4128 for (i = 0; i < set.used; ++i) {
4129 /* skip roots'n'stuff */
4130 if (set.val.snodes[i].type == LYXP_NODE_ELEM) {
4131 /* XPath expression cannot reference "lower" status than the node that has the definition */
4132 if (lyp_check_status(node->flags, lys_node_module(node), node->name, set.val.snodes[i].snode->flags,
4133 lys_node_module(set.val.snodes[i].snode), set.val.snodes[i].snode->name, node)) {
4134 return -1;
4135 }
4136
4137 if (parent) {
4138 for (elem = set.val.snodes[i].snode; elem && (elem != parent); elem = lys_parent(elem));
4139 if (!elem) {
4140 /* not in node's RPC or notification subtree, set the flag */
4141 node->flags |= LYS_VALID_DEP;
4142 break;
4143 }
4144 }
4145 }
4146 }
4147
4148 free(set.val.snodes);
4149 return EXIT_SUCCESS;
4150}
4151
4152/**
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004153 * @brief Passes config flag down to children, skips nodes without config flags.
4154 * Does not log.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004155 *
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004156 * @param[in] node Siblings and their children to have flags changed.
Michal Vaskoe022a562016-09-27 14:24:15 +02004157 * @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 +02004158 * @param[in] flags Flags to assign to all the nodes.
Michal Vaskoa86508c2016-08-26 14:30:19 +02004159 *
4160 * @return 0 on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004161 */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004162static int
Michal Vasko9e635ac2016-10-17 11:44:09 +02004163inherit_config_flag(struct lys_node *node, int flags, int clear, int check_list, int check_xpath)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004164{
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004165 assert(!(flags ^ (flags & LYS_CONFIG_MASK)));
Radek Krejci1d82ef62015-08-07 14:44:40 +02004166 LY_TREE_FOR(node, node) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004167 if (check_xpath && check_node_xpath(node)) {
4168 return -1;
4169 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004170 if (clear) {
4171 node->flags &= ~LYS_CONFIG_MASK;
Michal Vaskoc2a8d362016-09-29 08:50:13 +02004172 node->flags &= ~LYS_CONFIG_SET;
Michal Vaskoe022a562016-09-27 14:24:15 +02004173 } else {
4174 if (node->flags & LYS_CONFIG_SET) {
4175 /* skip nodes with an explicit config value */
4176 if ((flags & LYS_CONFIG_R) && (node->flags & LYS_CONFIG_W)) {
4177 LOGVAL(LYE_INARG, LY_VLOG_LYS, node, "true", "config");
4178 LOGVAL(LYE_SPEC, LY_VLOG_LYS, node, "State nodes cannot have configuration nodes as children.");
4179 return -1;
4180 }
4181 continue;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004182 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004183
4184 if (!(node->nodetype & (LYS_USES | LYS_GROUPING))) {
4185 node->flags = (node->flags & ~LYS_CONFIG_MASK) | flags;
4186 /* check that configuration lists have keys */
4187 if (check_list && (node->nodetype == LYS_LIST)
4188 && (node->flags & LYS_CONFIG_W) && !((struct lys_node_list *)node)->keys_size) {
4189 LOGVAL(LYE_MISSCHILDSTMT, LY_VLOG_LYS, node, "key", "list");
4190 return -1;
4191 }
4192 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004193 }
Radek Krejcibf2abff2016-08-23 15:51:52 +02004194 if (!(node->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA))) {
Michal Vasko9e635ac2016-10-17 11:44:09 +02004195 if (inherit_config_flag(node->child, flags, clear, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004196 return -1;
4197 }
Radek Krejci3a5501d2016-07-18 22:03:34 +02004198 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004199 }
Michal Vaskoa86508c2016-08-26 14:30:19 +02004200
4201 return 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004202}
4203
Michal Vasko730dfdf2015-08-11 14:48:05 +02004204/**
Michal Vasko7178e692016-02-12 15:58:05 +01004205 * @brief Resolve augment target. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004206 *
Michal Vaskobb211122015-08-19 14:03:11 +02004207 * @param[in] aug Augment to use.
Michal Vasko3edeaf72016-02-11 13:17:43 +01004208 * @param[in] siblings Nodes where to start the search in. If set, uses augment, if not, standalone augment.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004209 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004210 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004211 */
Michal Vasko7178e692016-02-12 15:58:05 +01004212static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004213resolve_augment(struct lys_node_augment *aug, struct lys_node *siblings)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004214{
Michal Vaskoe022a562016-09-27 14:24:15 +02004215 int rc, clear_config;
Michal Vasko1d87a922015-08-21 12:57:16 +02004216 struct lys_node *sub;
Pavol Vican47319932016-08-29 09:14:47 +02004217 const struct lys_node *aug_target, *parent;
Radek Krejci27fe55e2016-09-13 17:13:35 +02004218 struct lys_module *mod;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004219
Michal Vasko15b36692016-08-26 15:29:54 +02004220 assert(aug && !aug->target);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004221
Michal Vasko15b36692016-08-26 15:29:54 +02004222 /* resolve target node */
4223 rc = resolve_augment_schema_nodeid(aug->target_name, siblings, (siblings ? NULL : aug->module), &aug_target);
4224 if (rc == -1) {
4225 return -1;
4226 }
4227 if (rc > 0) {
4228 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, aug, aug->target_name[rc - 1], &aug->target_name[rc - 1]);
4229 return -1;
4230 }
4231 if (!aug_target) {
4232 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, aug, "augment", aug->target_name);
4233 return EXIT_FAILURE;
4234 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004235
Radek Krejci27fe55e2016-09-13 17:13:35 +02004236 /* check that we want to connect augment into its target */
4237 mod = lys_main_module(aug->module);
4238 if (!mod->implemented) {
4239 /* it must be augment only to the same module,
4240 * otherwise we do not apply augment in not-implemented
4241 * module. If the module is set to be implemented in future,
4242 * the augment is being resolved and checked again */
4243 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4244 if (lys_node_module(sub) != mod) {
4245 /* this is not an implemented module and the augment
4246 * target some other module, so avoid its connecting
4247 * to the target */
4248 return EXIT_SUCCESS;
4249 }
4250 }
4251 }
4252
Michal Vasko15b36692016-08-26 15:29:54 +02004253 if (!aug->child) {
4254 /* nothing to do */
4255 LOGWRN("Augment \"%s\" without children.", aug->target_name);
Radek Krejci27fe55e2016-09-13 17:13:35 +02004256 goto success;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004257 }
4258
Michal Vaskod58d5962016-03-02 14:29:41 +01004259 /* check for mandatory nodes - if the target node is in another module
4260 * the added nodes cannot be mandatory
4261 */
Michal Vasko15b36692016-08-26 15:29:54 +02004262 if (!aug->parent && (lys_node_module((struct lys_node *)aug) != lys_node_module(aug_target))
Radek Krejcie00d2312016-08-12 15:27:49 +02004263 && (rc = lyp_check_mandatory_augment(aug))) {
4264 return rc;
Michal Vaskod58d5962016-03-02 14:29:41 +01004265 }
4266
Michal Vasko07e89ef2016-03-03 13:28:57 +01004267 /* check augment target type and then augment nodes type */
Michal Vasko15b36692016-08-26 15:29:54 +02004268 if (aug_target->nodetype & (LYS_CONTAINER | LYS_LIST | LYS_CASE | LYS_INPUT | LYS_OUTPUT | LYS_NOTIF)) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004269 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004270 if (!(sub->nodetype & (LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST | LYS_USES | LYS_CHOICE))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004271 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4272 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004273 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004274 return -1;
4275 }
4276 }
Michal Vasko15b36692016-08-26 15:29:54 +02004277 } else if (aug_target->nodetype == LYS_CHOICE) {
Michal Vasko07e89ef2016-03-03 13:28:57 +01004278 LY_TREE_FOR(aug->child, sub) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004279 if (!(sub->nodetype & (LYS_CASE | LYS_ANYDATA | LYS_CONTAINER | LYS_LEAF | LYS_LIST | LYS_LEAFLIST))) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004280 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_LYS, aug, strnodetype(sub->nodetype), "augment");
4281 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Cannot augment \"%s\" with a \"%s\".",
Michal Vasko15b36692016-08-26 15:29:54 +02004282 strnodetype(aug_target->nodetype), strnodetype(sub->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004283 return -1;
4284 }
4285 }
4286 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01004287 LOGVAL(LYE_INARG, LY_VLOG_LYS, aug, aug->target_name, "target-node");
Michal Vasko15b36692016-08-26 15:29:54 +02004288 LOGVAL(LYE_SPEC, LY_VLOG_LYS, aug, "Invalid augment target node type \"%s\".", strnodetype(aug_target->nodetype));
Michal Vasko07e89ef2016-03-03 13:28:57 +01004289 return -1;
4290 }
4291
Radek Krejcic071c542016-01-27 14:57:51 +01004292 /* check identifier uniqueness as in lys_node_addchild() */
Michal Vasko1d87a922015-08-21 12:57:16 +02004293 LY_TREE_FOR(aug->child, sub) {
Michal Vasko15b36692016-08-26 15:29:54 +02004294 if (lys_check_id(sub, (struct lys_node *)aug_target, NULL)) {
Michal Vasko3e6665f2015-08-17 14:00:38 +02004295 return -1;
Radek Krejci07911992015-08-14 15:13:31 +02004296 }
4297 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004298
Michal Vasko15b36692016-08-26 15:29:54 +02004299 /* finally reconnect augmenting data into the target - add them to the target child list,
4300 * by setting aug->target we know the augment is fully resolved now */
4301 aug->target = (struct lys_node *)aug_target;
4302 if (aug->target->child) {
4303 sub = aug->target->child->prev; /* remember current target's last node */
4304 sub->next = aug->child; /* connect augmenting data after target's last node */
4305 aug->target->child->prev = aug->child->prev; /* new target's last node is last augmenting node */
4306 aug->child->prev = sub; /* finish connecting of both child lists */
4307 } else {
4308 aug->target->child = aug->child;
4309 }
4310
Michal Vasko9e635ac2016-10-17 11:44:09 +02004311 /* inherit config information from actual parent */
4312 for(parent = aug_target; parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC)); parent = lys_parent(parent));
4313 clear_config = (parent) ? 1 : 0;
4314 LY_TREE_FOR(aug->child, sub) {
4315 if (inherit_config_flag(sub, aug_target->flags & LYS_CONFIG_MASK, clear_config, 1, 1)) {
4316 return -1;
4317 }
4318 }
4319
Radek Krejci27fe55e2016-09-13 17:13:35 +02004320success:
4321 if (mod->implemented) {
4322 /* make target modules also implemented */
4323 for (sub = aug->target; sub; sub = lys_parent(sub)) {
4324 if (lys_set_implemented(sub->module)) {
4325 return -1;
4326 }
4327 }
4328 }
4329
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004330 return EXIT_SUCCESS;
4331}
4332
Michal Vasko730dfdf2015-08-11 14:48:05 +02004333/**
Pavol Vican855ca622016-09-05 13:07:54 +02004334 * @brief Resolve (find) choice default case. Does not log.
4335 *
4336 * @param[in] choic Choice to use.
4337 * @param[in] dflt Name of the default case.
4338 *
4339 * @return Pointer to the default node or NULL.
4340 */
4341static struct lys_node *
4342resolve_choice_dflt(struct lys_node_choice *choic, const char *dflt)
4343{
4344 struct lys_node *child, *ret;
4345
4346 LY_TREE_FOR(choic->child, child) {
4347 if (child->nodetype == LYS_USES) {
4348 ret = resolve_choice_dflt((struct lys_node_choice *)child, dflt);
4349 if (ret) {
4350 return ret;
4351 }
4352 }
4353
4354 if (ly_strequal(child->name, dflt, 1) && (child->nodetype & (LYS_ANYDATA | LYS_CASE
Radek Krejci2f792db2016-09-12 10:52:33 +02004355 | LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_CHOICE))) {
Pavol Vican855ca622016-09-05 13:07:54 +02004356 return child;
4357 }
4358 }
4359
4360 return NULL;
4361}
4362
4363/**
Michal Vasko730dfdf2015-08-11 14:48:05 +02004364 * @brief Resolve uses, apply augments, refines. Logs directly.
4365 *
Michal Vaskobb211122015-08-19 14:03:11 +02004366 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004367 * @param[in,out] unres List of unresolved items.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004368 *
Michal Vaskodef0db12015-10-07 13:22:48 +02004369 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004370 */
Michal Vasko184521f2015-09-24 13:14:26 +02004371static int
Radek Krejci48464ed2016-03-17 15:44:09 +01004372resolve_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004373{
4374 struct ly_ctx *ctx;
Pavol Vican855ca622016-09-05 13:07:54 +02004375 struct lys_node *node = NULL, *next, *iter, **refine_nodes = NULL;
Pavol Vican55abd332016-07-12 15:54:49 +02004376 struct lys_node *node_aux, *parent, *tmp;
Radek Krejci200bf712016-08-16 17:11:04 +02004377 struct lys_node_leaflist *llist;
4378 struct lys_node_leaf *leaf;
Radek Krejci76512572015-08-04 09:47:08 +02004379 struct lys_refine *rfn;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004380 struct lys_restr *must, **old_must;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004381 struct lys_iffeature *iff, **old_iff;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004382 int i, j, k, rc, parent_config, clear_config, check_list, check_xpath;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004383 uint8_t size, *old_size;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004384 unsigned int usize, usize1, usize2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004385
Michal Vasko71e1aa82015-08-12 12:17:51 +02004386 assert(uses->grp);
Michal Vaskoe7708512016-03-11 10:26:55 +01004387 /* HACK just check that the grouping is resolved */
Michal Vaskodef0db12015-10-07 13:22:48 +02004388 assert(!uses->grp->nacm);
Michal Vasko71e1aa82015-08-12 12:17:51 +02004389
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004390 if (!uses->grp->child) {
4391 /* grouping without children, warning was already displayed */
4392 return EXIT_SUCCESS;
4393 }
4394
4395 /* get proper parent (config) flags */
4396 for (node_aux = lys_parent((struct lys_node *)uses); node_aux && (node_aux->nodetype == LYS_USES); node_aux = lys_parent(node_aux));
4397 if (node_aux) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004398 parent_config = node_aux->flags & LYS_CONFIG_MASK;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004399 } else {
4400 /* default */
Michal Vaskoa86508c2016-08-26 14:30:19 +02004401 parent_config = LYS_CONFIG_W;
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004402 }
4403
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004404 /* copy the data nodes from grouping into the uses context */
Michal Vasko1e62a092015-12-01 12:27:20 +01004405 LY_TREE_FOR(uses->grp->child, node_aux) {
Michal Vaskoe022a562016-09-27 14:24:15 +02004406 node = lys_node_dup(uses->module, (struct lys_node *)uses, node_aux, uses->nacm, unres, 0);
Michal Vasko1e62a092015-12-01 12:27:20 +01004407 if (!node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004408 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, uses->grp->name, "uses");
4409 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Copying data from grouping failed.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004410 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004411 }
Pavol Vican55abd332016-07-12 15:54:49 +02004412 /* test the name of siblings */
4413 LY_TREE_FOR((uses->parent) ? uses->parent->child : lys_main_module(uses->module)->data, tmp) {
Pavol Vican2510ddc2016-07-18 16:23:44 +02004414 if (!(tmp->nodetype & (LYS_USES | LYS_GROUPING | LYS_CASE)) && ly_strequal(tmp->name, node_aux->name, 1)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004415 goto fail;
Pavol Vican55abd332016-07-12 15:54:49 +02004416 }
4417 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004418 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004419
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004420 ctx = uses->module->ctx;
Michal Vasko4bc590c2016-09-30 12:19:51 +02004421
4422 parent = node;
4423 while (parent && !(parent->nodetype & (LYS_NOTIF | LYS_INPUT | LYS_OUTPUT | LYS_RPC | LYS_GROUPING))) {
4424 if (parent->nodetype == LYS_AUGMENT) {
4425 if (!((struct lys_node_augment *)parent)->target) {
4426 break;
4427 } else {
4428 parent = ((struct lys_node_augment *)parent)->target;
4429 }
4430 } else {
4431 parent = parent->parent;
4432 }
4433 }
Michal Vaskoe022a562016-09-27 14:24:15 +02004434 if (parent) {
Michal Vasko4bc590c2016-09-30 12:19:51 +02004435 if (parent->nodetype & (LYS_GROUPING | LYS_AUGMENT)) {
4436 /* we are still in some other unresolved grouping or augment, unable to check lists */
Michal Vaskoe022a562016-09-27 14:24:15 +02004437 check_list = 0;
4438 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004439 check_xpath = 0;
Michal Vaskoe022a562016-09-27 14:24:15 +02004440 } else {
4441 check_list = 0;
4442 clear_config = 1;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004443 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004444 }
4445 } else {
4446 check_list = 1;
4447 clear_config = 0;
Michal Vasko9e635ac2016-10-17 11:44:09 +02004448 check_xpath = 1;
Michal Vaskoe022a562016-09-27 14:24:15 +02004449 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004450
Michal Vaskoa86508c2016-08-26 14:30:19 +02004451 if (parent_config) {
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004452 assert(uses->child);
Michal Vasko9e635ac2016-10-17 11:44:09 +02004453 if (inherit_config_flag(uses->child, parent_config, clear_config, check_list, check_xpath)) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004454 goto fail;
4455 }
Michal Vaskoaec34ea2016-05-19 15:21:40 +02004456 }
4457
Michal Vaskodef0db12015-10-07 13:22:48 +02004458 /* we managed to copy the grouping, the rest must be possible to resolve */
4459
Pavol Vican855ca622016-09-05 13:07:54 +02004460 if (uses->refine_size) {
4461 refine_nodes = malloc(uses->refine_size * sizeof *refine_nodes);
4462 if (!refine_nodes) {
4463 LOGMEM;
4464 goto fail;
4465 }
4466 }
4467
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004468 /* apply refines */
4469 for (i = 0; i < uses->refine_size; i++) {
4470 rfn = &uses->refine[i];
Michal Vasko3edeaf72016-02-11 13:17:43 +01004471 rc = resolve_descendant_schema_nodeid(rfn->target_name, uses->child, LYS_NO_RPC_NOTIF_NODE,
Radek Krejcif3c71de2016-04-11 12:45:46 +02004472 1, 0, (const struct lys_node **)&node);
Michal Vasko9bb061b2016-02-12 11:00:19 +01004473 if (rc || !node) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004474 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004475 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004476 }
4477
Radek Krejci1d82ef62015-08-07 14:44:40 +02004478 if (rfn->target_type && !(node->nodetype & rfn->target_type)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004479 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->target_name, "refine");
4480 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses, "Refine substatements not applicable to the target-node.");
Michal Vaskoa86508c2016-08-26 14:30:19 +02004481 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004482 }
Pavol Vican855ca622016-09-05 13:07:54 +02004483 refine_nodes[i] = node;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004484
4485 /* description on any nodetype */
4486 if (rfn->dsc) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004487 lydict_remove(ctx, node->dsc);
4488 node->dsc = lydict_insert(ctx, rfn->dsc, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004489 }
4490
4491 /* reference on any nodetype */
4492 if (rfn->ref) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004493 lydict_remove(ctx, node->ref);
4494 node->ref = lydict_insert(ctx, rfn->ref, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004495 }
4496
4497 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004498 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004499 node->flags &= ~LYS_CONFIG_MASK;
4500 node->flags |= (rfn->flags & LYS_CONFIG_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004501 }
4502
4503 /* default value ... */
Radek Krejci200bf712016-08-16 17:11:04 +02004504 if (rfn->dflt_size) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004505 if (node->nodetype == LYS_LEAF) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004506 /* leaf */
Radek Krejci200bf712016-08-16 17:11:04 +02004507 leaf = (struct lys_node_leaf *)node;
4508
4509 lydict_remove(ctx, leaf->dflt);
4510 leaf->dflt = lydict_insert(ctx, rfn->dflt[0], 0);
4511
4512 /* check the default value */
4513 if (unres_schema_add_str(leaf->module, unres, &leaf->type, UNRES_TYPE_DFLT, leaf->dflt) == -1) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004514 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004515 }
Radek Krejci200bf712016-08-16 17:11:04 +02004516 } else if (node->nodetype == LYS_LEAFLIST) {
4517 /* leaf-list */
4518 llist = (struct lys_node_leaflist *)node;
4519
4520 /* remove complete set of defaults in target */
4521 for (i = 0; i < llist->dflt_size; i++) {
4522 lydict_remove(ctx, llist->dflt[i]);
4523 }
4524 free(llist->dflt);
4525
4526 /* copy the default set from refine */
4527 llist->dflt_size = rfn->dflt_size;
4528 llist->dflt = malloc(llist->dflt_size * sizeof *llist->dflt);
4529 for (i = 0; i < llist->dflt_size; i++) {
4530 llist->dflt[i] = lydict_insert(ctx, rfn->dflt[i], 0);
4531 }
4532
4533 /* check default value */
4534 for (i = 0; i < llist->dflt_size; i++) {
4535 if (unres_schema_add_str(llist->module, unres, &llist->type, UNRES_TYPE_DFLT, llist->dflt[i]) == -1) {
Pavol Vican855ca622016-09-05 13:07:54 +02004536 goto fail;
Radek Krejci200bf712016-08-16 17:11:04 +02004537 }
4538 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004539 }
4540 }
4541
4542 /* mandatory on leaf, anyxml or choice */
Radek Krejci1574a8d2015-08-03 14:16:52 +02004543 if (rfn->flags & LYS_MAND_MASK) {
Radek Krejcibf2abff2016-08-23 15:51:52 +02004544 if (node->nodetype & (LYS_LEAF | LYS_ANYDATA | LYS_CHOICE)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004545 /* remove current value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004546 node->flags &= ~LYS_MAND_MASK;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004547
4548 /* set new value */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004549 node->flags |= (rfn->flags & LYS_MAND_MASK);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004550 }
Pavol Vican855ca622016-09-05 13:07:54 +02004551 if (rfn->flags & LYS_MAND_TRUE) {
4552 /* check if node has default value */
4553 if ((node->nodetype & LYS_LEAF) && ((struct lys_node_leaf *)node)->dflt) {
4554 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on leaf with \"default\".");
4555 goto fail;
4556 }
4557 if ((node->nodetype & LYS_CHOICE) && ((struct lys_node_choice *)node)->dflt) {
4558 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "The \"mandatory\" statement is forbidden on choices with \"default\".");
4559 goto fail;
4560 }
4561 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004562 }
4563
4564 /* presence on container */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004565 if ((node->nodetype & LYS_CONTAINER) && rfn->mod.presence) {
4566 lydict_remove(ctx, ((struct lys_node_container *)node)->presence);
4567 ((struct lys_node_container *)node)->presence = lydict_insert(ctx, rfn->mod.presence, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004568 }
4569
4570 /* min/max-elements on list or leaf-list */
Radek Krejci1d82ef62015-08-07 14:44:40 +02004571 if (node->nodetype == LYS_LIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004572 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004573 ((struct lys_node_list *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004574 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004575 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004576 ((struct lys_node_list *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004577 }
Radek Krejci1d82ef62015-08-07 14:44:40 +02004578 } else if (node->nodetype == LYS_LEAFLIST) {
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004579 if (rfn->flags & LYS_RFN_MINSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004580 ((struct lys_node_leaflist *)node)->min = rfn->mod.list.min;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004581 }
Radek Krejci0f04a6c2016-04-14 16:16:36 +02004582 if (rfn->flags & LYS_RFN_MAXSET) {
Radek Krejci1d82ef62015-08-07 14:44:40 +02004583 ((struct lys_node_leaflist *)node)->max = rfn->mod.list.max;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004584 }
4585 }
4586
4587 /* must in leaf, leaf-list, list, container or anyxml */
4588 if (rfn->must_size) {
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004589 switch (node->nodetype) {
4590 case LYS_LEAF:
4591 old_size = &((struct lys_node_leaf *)node)->must_size;
4592 old_must = &((struct lys_node_leaf *)node)->must;
4593 break;
4594 case LYS_LEAFLIST:
4595 old_size = &((struct lys_node_leaflist *)node)->must_size;
4596 old_must = &((struct lys_node_leaflist *)node)->must;
4597 break;
4598 case LYS_LIST:
4599 old_size = &((struct lys_node_list *)node)->must_size;
4600 old_must = &((struct lys_node_list *)node)->must;
4601 break;
4602 case LYS_CONTAINER:
4603 old_size = &((struct lys_node_container *)node)->must_size;
4604 old_must = &((struct lys_node_container *)node)->must;
4605 break;
4606 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02004607 case LYS_ANYDATA:
4608 old_size = &((struct lys_node_anydata *)node)->must_size;
4609 old_must = &((struct lys_node_anydata *)node)->must;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004610 break;
4611 default:
4612 LOGINT;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004613 goto fail;
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004614 }
4615
4616 size = *old_size + rfn->must_size;
4617 must = realloc(*old_must, size * sizeof *rfn->must);
4618 if (!must) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004619 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004620 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004621 }
Pavol Vican855ca622016-09-05 13:07:54 +02004622 for (k = 0, j = *old_size; k < rfn->must_size; k++, j++) {
4623 must[j].expr = lydict_insert(ctx, rfn->must[k].expr, 0);
4624 must[j].dsc = lydict_insert(ctx, rfn->must[k].dsc, 0);
4625 must[j].ref = lydict_insert(ctx, rfn->must[k].ref, 0);
4626 must[j].eapptag = lydict_insert(ctx, rfn->must[k].eapptag, 0);
4627 must[j].emsg = lydict_insert(ctx, rfn->must[k].emsg, 0);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004628 }
4629
Michal Vaskoef2fdc82015-09-24 09:54:42 +02004630 *old_must = must;
4631 *old_size = size;
Michal Vasko508a50d2016-09-07 14:50:33 +02004632
4633 /* check XPath dependencies again */
4634 if (unres_schema_add_node(node->module, unres, node, UNRES_XPATH, NULL) == -1) {
4635 goto fail;
4636 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004637 }
Radek Krejci363bd4a2016-07-29 14:30:20 +02004638
4639 /* if-feature in leaf, leaf-list, list, container or anyxml */
4640 if (rfn->iffeature_size) {
4641 old_size = &node->iffeature_size;
4642 old_iff = &node->iffeature;
4643
4644 size = *old_size + rfn->iffeature_size;
4645 iff = realloc(*old_iff, size * sizeof *rfn->iffeature);
4646 if (!iff) {
4647 LOGMEM;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004648 goto fail;
Radek Krejci363bd4a2016-07-29 14:30:20 +02004649 }
Pavol Vican855ca622016-09-05 13:07:54 +02004650 for (k = 0, j = *old_size; k < rfn->iffeature_size; k++, j++) {
4651 resolve_iffeature_getsizes(&rfn->iffeature[k], &usize1, &usize2);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004652 if (usize1) {
4653 /* there is something to duplicate */
4654 /* duplicate compiled expression */
4655 usize = (usize1 / 4) + (usize1 % 4) ? 1 : 0;
4656 iff[j].expr = malloc(usize * sizeof *iff[j].expr);
Pavol Vican855ca622016-09-05 13:07:54 +02004657 memcpy(iff[j].expr, rfn->iffeature[k].expr, usize * sizeof *iff[j].expr);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004658
4659 /* duplicate list of feature pointers */
Pavol Vican855ca622016-09-05 13:07:54 +02004660 iff[j].features = malloc(usize2 * sizeof *iff[k].features);
4661 memcpy(iff[j].features, rfn->iffeature[k].features, usize2 * sizeof *iff[j].features);
Radek Krejci363bd4a2016-07-29 14:30:20 +02004662 }
4663 }
4664
4665 *old_iff = iff;
4666 *old_size = size;
4667 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004668 }
4669
4670 /* apply augments */
4671 for (i = 0; i < uses->augment_size; i++) {
Radek Krejci48464ed2016-03-17 15:44:09 +01004672 rc = resolve_augment(&uses->augment[i], uses->child);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004673 if (rc) {
Michal Vaskoa86508c2016-08-26 14:30:19 +02004674 goto fail;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004675 }
4676 }
4677
Pavol Vican855ca622016-09-05 13:07:54 +02004678 /* check refines */
4679 for (i = 0; i < uses->refine_size; i++) {
4680 node = refine_nodes[i];
4681 rfn = &uses->refine[i];
4682
4683 /* config on any nodetype */
Michal Vaskoe022a562016-09-27 14:24:15 +02004684 if ((rfn->flags & LYS_CONFIG_MASK) && !clear_config) {
Pavol Vican855ca622016-09-05 13:07:54 +02004685 for (parent = lys_parent(node); parent && parent->nodetype == LYS_USES; parent = lys_parent(parent));
4686 if (parent && parent->nodetype != LYS_GROUPING &&
4687 ((parent->flags & LYS_CONFIG_MASK) != (rfn->flags & LYS_CONFIG_MASK)) &&
4688 (rfn->flags & LYS_CONFIG_W)) {
4689 /* setting config true under config false is prohibited */
4690 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4691 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4692 "changing config from 'false' to 'true' is prohibited while "
4693 "the target's parent is still config 'false'.");
4694 goto fail;
4695 }
4696
4697 /* inherit config change to the target children */
4698 LY_TREE_DFS_BEGIN(node->child, next, iter) {
4699 if (rfn->flags & LYS_CONFIG_W) {
4700 if (iter->flags & LYS_CONFIG_SET) {
4701 /* config is set explicitely, go to next sibling */
4702 next = NULL;
4703 goto nextsibling;
4704 }
4705 } else { /* LYS_CONFIG_R */
4706 if ((iter->flags & LYS_CONFIG_SET) && (iter->flags & LYS_CONFIG_W)) {
4707 /* error - we would have config data under status data */
4708 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, "config", "refine");
4709 LOGVAL(LYE_SPEC, LY_VLOG_LYS, uses,
4710 "changing config from 'true' to 'false' is prohibited while the target "
4711 "has still a children with explicit config 'true'.");
4712 goto fail;
4713 }
4714 }
4715 /* change config */
4716 iter->flags &= ~LYS_CONFIG_MASK;
4717 iter->flags |= (rfn->flags & LYS_CONFIG_MASK);
4718
4719 /* select next iter - modified LY_TREE_DFS_END */
4720 if (iter->nodetype & (LYS_LEAF | LYS_LEAFLIST | LYS_ANYDATA)) {
4721 next = NULL;
4722 } else {
4723 next = iter->child;
4724 }
4725nextsibling:
4726 if (!next) {
4727 /* try siblings */
4728 next = iter->next;
4729 }
4730 while (!next) {
4731 /* parent is already processed, go to its sibling */
4732 iter = lys_parent(iter);
4733
4734 /* no siblings, go back through parents */
4735 if (iter == node) {
4736 /* we are done, no next element to process */
4737 break;
4738 }
4739 next = iter->next;
4740 }
4741 }
4742 }
4743
4744 /* default value */
4745 if (rfn->dflt_size && node->nodetype == LYS_CHOICE) {
4746 /* choice */
4747
4748 ((struct lys_node_choice *)node)->dflt = resolve_choice_dflt((struct lys_node_choice *)node,
4749 rfn->dflt[0]);
4750 if (!((struct lys_node_choice *)node)->dflt) {
4751 LOGVAL(LYE_INARG, LY_VLOG_LYS, uses, rfn->dflt[0], "default");
4752 goto fail;
4753 }
4754 if (lyp_check_mandatory_choice(node)) {
4755 goto fail;
4756 }
4757 }
4758
4759 /* min/max-elements on list or leaf-list */
4760 if (node->nodetype == LYS_LIST) {
4761 if (((struct lys_node_list *)node)->min > ((struct lys_node_list *)node)->max) {
4762 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4763 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4764 goto fail;
4765 }
4766 } else if (node->nodetype == LYS_LEAFLIST) {
4767 if (((struct lys_node_leaflist *)node)->min > ((struct lys_node_leaflist *)node)->max) {
4768 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Invalid value \"%d\" of \"%s\".", rfn->mod.list.min, "min-elements");
4769 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "\"min-elements\" is bigger than \"max-elements\".");
4770 goto fail;
4771 }
4772 }
4773
4774 /* additional checks */
4775 if (node->nodetype == LYS_LEAFLIST) {
4776 llist = (struct lys_node_leaflist *)node;
4777 if (llist->dflt_size && llist->min) {
4778 LOGVAL(LYE_INCHILDSTMT, LY_VLOG_NONE, NULL, rfn->dflt_size ? "default" : "min-elements", "refine");
4779 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL,
4780 "The \"min-elements\" statement with non-zero value is forbidden on leaf-lists with the \"default\" statement.");
4781 goto fail;
4782 }
4783 }
4784 if ((rfn->flags & LYS_MAND_TRUE) || rfn->mod.list.min) {
4785 /* check for mandatory node in default case, first find the closest parent choice to the changed node */
4786 for (parent = node->parent;
4787 parent && !(parent->nodetype & (LYS_CHOICE | LYS_GROUPING | LYS_ACTION | LYS_USES));
4788 parent = parent->parent) {
4789 if (parent->nodetype == LYS_CONTAINER && ((struct lys_node_container *)parent)->presence) {
4790 /* stop also on presence containers */
4791 break;
4792 }
4793 }
4794 /* and if it is a choice with the default case, check it for presence of a mandatory node in it */
4795 if (parent && parent->nodetype == LYS_CHOICE && ((struct lys_node_choice *)parent)->dflt) {
4796 if (lyp_check_mandatory_choice(parent)) {
4797 goto fail;
4798 }
4799 }
4800 }
4801 }
4802 free(refine_nodes);
4803
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004804 return EXIT_SUCCESS;
Michal Vaskoa86508c2016-08-26 14:30:19 +02004805
4806fail:
4807 LY_TREE_FOR_SAFE(uses->child, next, iter) {
4808 lys_node_free(iter, NULL, 0);
4809 }
Pavol Vican855ca622016-09-05 13:07:54 +02004810 free(refine_nodes);
Michal Vaskoa86508c2016-08-26 14:30:19 +02004811 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004812}
4813
Radek Krejci018f1f52016-08-03 16:01:20 +02004814static int
4815identity_backlink_update(struct lys_ident *der, struct lys_ident *base)
4816{
4817 int i;
4818
4819 assert(der && base);
4820
4821 base->der = ly_realloc(base->der, (base->der_size + 1) * sizeof *(base->der));
4822 if (!base->der) {
4823 LOGMEM;
4824 return EXIT_FAILURE;
4825 }
4826 base->der[base->der_size++] = der;
4827
4828 for (i = 0; i < base->base_size; i++) {
4829 if (identity_backlink_update(der, base->base[i])) {
4830 return EXIT_FAILURE;
4831 }
4832 }
4833
4834 return EXIT_SUCCESS;
4835}
4836
Michal Vasko730dfdf2015-08-11 14:48:05 +02004837/**
4838 * @brief Resolve base identity recursively. Does not log.
4839 *
4840 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004841 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004842 * @param[in] basename Base name of the identity.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004843 * @param[out] ret Pointer to the resolved identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004844 *
Radek Krejci219fa612016-08-15 10:36:51 +02004845 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on crucial error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004846 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004847static int
Michal Vasko1e62a092015-12-01 12:27:20 +01004848resolve_base_ident_sub(const struct lys_module *module, struct lys_ident *ident, const char *basename,
Radek Krejci018f1f52016-08-03 16:01:20 +02004849 struct unres_schema *unres, struct lys_ident **ret)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004850{
Michal Vaskof02e3742015-08-05 16:27:02 +02004851 uint32_t i, j;
Radek Krejci018f1f52016-08-03 16:01:20 +02004852 struct lys_ident *base = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004853
Radek Krejcicf509982015-12-15 09:22:44 +01004854 assert(ret);
4855
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004856 /* search module */
4857 for (i = 0; i < module->ident_size; i++) {
4858 if (!strcmp(basename, module->ident[i].name)) {
4859
4860 if (!ident) {
4861 /* just search for type, so do not modify anything, just return
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004862 * the base identity pointer */
Radek Krejcicf509982015-12-15 09:22:44 +01004863 *ret = &module->ident[i];
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004864 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004865 }
4866
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004867 base = &module->ident[i];
4868 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004869 }
4870 }
4871
4872 /* search submodules */
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004873 for (j = 0; j < module->inc_size && module->inc[j].submodule; j++) {
4874 for (i = 0; i < module->inc[j].submodule->ident_size; i++) {
4875 if (!strcmp(basename, module->inc[j].submodule->ident[i].name)) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004876
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004877 if (!ident) {
4878 *ret = &module->inc[j].submodule->ident[i];
4879 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004880 }
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004881
4882 base = &module->inc[j].submodule->ident[i];
4883 goto matchfound;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004884 }
4885 }
4886 }
4887
Radek Krejcif2ac7ae2016-02-19 13:38:07 +01004888matchfound:
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004889 /* we found it somewhere */
Radek Krejcibabbff82016-02-19 13:31:37 +01004890 if (base) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004891 /* is it already completely resolved? */
4892 for (i = 0; i < unres->count; i++) {
Radek Krejciba7b1cc2016-08-08 13:44:43 +02004893 if ((unres->item[i] == base) && (unres->type[i] == UNRES_IDENT)) {
Radek Krejci018f1f52016-08-03 16:01:20 +02004894 /* identity found, but not yet resolved, so do not return it in *res and try it again later */
4895
4896 /* simple check for circular reference,
4897 * the complete check is done as a side effect of using only completely
4898 * resolved identities (previous check of unres content) */
4899 if (ly_strequal((const char *)unres->str_snode[i], ident->name, 1)) {
4900 LOGVAL(LYE_INARG, LY_VLOG_NONE, NULL, basename, "base");
4901 LOGVAL(LYE_SPEC, LY_VLOG_NONE, NULL, "Circular reference of \"%s\" identity.", basename);
Radek Krejci219fa612016-08-15 10:36:51 +02004902 return -1;
Radek Krejci018f1f52016-08-03 16:01:20 +02004903 }
4904
Radek Krejci06f64ed2016-08-15 11:07:44 +02004905 return EXIT_FAILURE;
Radek Krejcibabbff82016-02-19 13:31:37 +01004906 }
4907 }
Radek Krejci018f1f52016-08-03 16:01:20 +02004908
Radek Krejcibabbff82016-02-19 13:31:37 +01004909 /* checks done, store the result */
Radek Krejci018f1f52016-08-03 16:01:20 +02004910 *ret = base;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004911 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004912 }
4913
Radek Krejci219fa612016-08-15 10:36:51 +02004914 /* base not found (maybe a forward reference) */
4915 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004916}
4917
Michal Vasko730dfdf2015-08-11 14:48:05 +02004918/**
4919 * @brief Resolve base identity. Logs directly.
4920 *
4921 * @param[in] module Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02004922 * @param[in] ident Identity to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004923 * @param[in] basename Base name of the identity.
Radek Krejcibabbff82016-02-19 13:31:37 +01004924 * @param[in] parent Either "type" or "identity".
Radek Krejcicf509982015-12-15 09:22:44 +01004925 * @param[in,out] type Type structure where we want to resolve identity. Can be NULL.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004926 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004927 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02004928 */
Michal Vasko3ab70fc2015-08-17 14:06:23 +02004929static int
Michal Vaskof2d43962016-09-02 11:10:16 +02004930resolve_base_ident(const struct lys_module *module, struct lys_ident *ident, const char *basename, const char *parent,
Radek Krejci018f1f52016-08-03 16:01:20 +02004931 struct lys_type *type, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004932{
4933 const char *name;
Radek Krejci219fa612016-08-15 10:36:51 +02004934 int mod_name_len = 0, rc;
Radek Krejcicf509982015-12-15 09:22:44 +01004935 struct lys_ident *target, **ret;
Radek Krejci4372b4e2016-04-14 17:42:16 +02004936 uint16_t flags;
Radek Krejcicf509982015-12-15 09:22:44 +01004937 struct lys_module *mod;
4938
4939 assert((ident && !type) || (!ident && type));
4940
4941 if (!type) {
4942 /* have ident to resolve */
4943 ret = &target;
4944 flags = ident->flags;
4945 mod = ident->module;
4946 } else {
4947 /* have type to fill */
Michal Vaskof2d43962016-09-02 11:10:16 +02004948 ++type->info.ident.count;
4949 type->info.ident.ref = ly_realloc(type->info.ident.ref, type->info.ident.count * sizeof *type->info.ident.ref);
4950 if (!type->info.ident.ref) {
4951 LOGMEM;
4952 return -1;
4953 }
4954
4955 ret = &type->info.ident.ref[type->info.ident.count - 1];
Radek Krejcicf509982015-12-15 09:22:44 +01004956 flags = type->parent->flags;
4957 mod = type->parent->module;
4958 }
Michal Vaskof2006002016-04-21 16:28:15 +02004959 *ret = NULL;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004960
4961 /* search for the base identity */
4962 name = strchr(basename, ':');
4963 if (name) {
4964 /* set name to correct position after colon */
Michal Vasko2d851a92015-10-20 16:16:36 +02004965 mod_name_len = name - basename;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004966 name++;
4967
Michal Vasko2d851a92015-10-20 16:16:36 +02004968 if (!strncmp(basename, module->name, mod_name_len) && !module->name[mod_name_len]) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004969 /* prefix refers to the current module, ignore it */
Michal Vasko2d851a92015-10-20 16:16:36 +02004970 mod_name_len = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004971 }
4972 } else {
4973 name = basename;
4974 }
4975
Radek Krejcic071c542016-01-27 14:57:51 +01004976 /* get module where to search */
4977 module = lys_get_import_module(module, NULL, 0, mod_name_len ? basename : NULL, mod_name_len);
4978 if (!module) {
4979 /* identity refers unknown data model */
Radek Krejci02a04992016-03-17 16:06:37 +01004980 LOGVAL(LYE_INMOD, LY_VLOG_NONE, NULL, basename);
Radek Krejcic071c542016-01-27 14:57:51 +01004981 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02004982 }
4983
Radek Krejcic071c542016-01-27 14:57:51 +01004984 /* search in the identified module ... */
Radek Krejci219fa612016-08-15 10:36:51 +02004985 rc = resolve_base_ident_sub(module, ident, name, unres, ret);
4986 if (!rc) {
4987 assert(*ret);
4988
4989 /* check status */
4990 if (lyp_check_status(flags, mod, ident ? ident->name : "of type",
4991 (*ret)->flags, (*ret)->module, (*ret)->name, NULL)) {
4992 rc = -1;
Pavol Vicanfdab9f92016-09-07 15:23:27 +02004993 } else {
4994 if (ident) {
4995 ident->base[ident->base_size++] = *ret;
4996
4997 /* maintain backlinks to the derived identities */
4998 rc = identity_backlink_update(ident, *ret) ? -1 : EXIT_SUCCESS;
4999 }
Radek Krejci219fa612016-08-15 10:36:51 +02005000 }
5001 } else if (rc == EXIT_FAILURE) {
5002 LOGVAL(LYE_INRESOLV, LY_VLOG_NONE, NULL, parent, basename);
Pavol Vican053a2882016-09-05 14:40:33 +02005003 if (type) {
5004 --type->info.ident.count;
5005 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005006 }
5007
Radek Krejci219fa612016-08-15 10:36:51 +02005008 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005009}
5010
Michal Vasko730dfdf2015-08-11 14:48:05 +02005011/**
Michal Vaskof39142b2015-10-21 11:40:05 +02005012 * @brief Resolve JSON data format identityref. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005013 *
Michal Vaskof2d43962016-09-02 11:10:16 +02005014 * @param[in] type Identityref type.
Michal Vaskofb0873c2015-08-21 09:00:07 +02005015 * @param[in] ident_name Identityref name.
Radek Krejciadb57612016-02-16 13:34:34 +01005016 * @param[in] node Node where the identityref is being resolved
Michal Vasko730dfdf2015-08-11 14:48:05 +02005017 *
5018 * @return Pointer to the identity resolvent, NULL on error.
5019 */
Radek Krejcia52656e2015-08-05 13:41:50 +02005020struct lys_ident *
Michal Vaskof2d43962016-09-02 11:10:16 +02005021resolve_identref(struct lys_type *type, const char *ident_name, struct lyd_node *node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005022{
Michal Vaskoc633ca02015-08-21 14:03:51 +02005023 const char *mod_name, *name;
Michal Vaskof2d43962016-09-02 11:10:16 +02005024 int mod_name_len, rc, i, j;
5025 struct lys_ident *der, *cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005026
Michal Vaskof2d43962016-09-02 11:10:16 +02005027 if (!type || (!type->info.ident.count && !type->der) || !ident_name) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005028 return NULL;
5029 }
5030
Michal Vaskoc633ca02015-08-21 14:03:51 +02005031 rc = parse_node_identifier(ident_name, &mod_name, &mod_name_len, &name, NULL);
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005032 if (rc < 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005033 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[-rc], &ident_name[-rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005034 return NULL;
Michal Vaskob43bb3c2016-03-17 15:00:27 +01005035 } else if (rc < (signed)strlen(ident_name)) {
Radek Krejci02a04992016-03-17 16:06:37 +01005036 LOGVAL(LYE_INCHAR, LY_VLOG_LYD, node, ident_name[rc], &ident_name[rc]);
Michal Vaskofb0873c2015-08-21 09:00:07 +02005037 return NULL;
5038 }
5039
Michal Vaskof2d43962016-09-02 11:10:16 +02005040 /* go through all the bases in all the derived types */
5041 while (type->der) {
5042 for (i = 0; i < type->info.ident.count; ++i) {
5043 cur = type->info.ident.ref[i];
5044 if (!strcmp(cur->name, name) && (!mod_name
5045 || (!strncmp(cur->module->name, mod_name, mod_name_len) && !cur->module->name[mod_name_len]))) {
5046 goto match;
5047 }
Michal Vaskofb0873c2015-08-21 09:00:07 +02005048
Michal Vaskof2d43962016-09-02 11:10:16 +02005049 for (j = 0; j < cur->der_size; j++) {
5050 der = cur->der[j]; /* shortcut */
5051 if (!strcmp(der->name, name) &&
5052 (!mod_name || (!strncmp(der->module->name, mod_name, mod_name_len) && !der->module->name[mod_name_len]))) {
5053 /* we have match */
5054 cur = der;
5055 goto match;
5056 }
5057 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005058 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005059 type = &type->der->type;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005060 }
5061
Radek Krejci48464ed2016-03-17 15:44:09 +01005062 LOGVAL(LYE_INRESOLV, LY_VLOG_LYD, node, "identityref", ident_name);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005063 return NULL;
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005064
5065match:
Michal Vaskof2d43962016-09-02 11:10:16 +02005066 for (i = 0; i < cur->iffeature_size; i++) {
5067 if (!resolve_iffeature(&cur->iffeature[i])) {
5068 LOGVAL(LYE_INVAL, LY_VLOG_LYD, node, cur->name, node->schema->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005069 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, "Identity \"%s\" is disabled by its if-feature condition.",
Michal Vaskof2d43962016-09-02 11:10:16 +02005070 cur->name);
Radek Krejcif1ee2e22016-08-02 16:36:48 +02005071 return NULL;
5072 }
5073 }
Michal Vaskof2d43962016-09-02 11:10:16 +02005074 return cur;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005075}
5076
Michal Vasko730dfdf2015-08-11 14:48:05 +02005077/**
Michal Vaskobb211122015-08-19 14:03:11 +02005078 * @brief Resolve unresolved uses. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005079 *
Michal Vaskobb211122015-08-19 14:03:11 +02005080 * @param[in] uses Uses to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005081 * @param[in] unres Specific unres item.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005082 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005083 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005084 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005085static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005086resolve_unres_schema_uses(struct lys_node_uses *uses, struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005087{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005088 int rc;
Radek Krejci010e54b2016-03-15 09:40:34 +01005089 struct lys_node *par_grp;
Michal Vaskoe91afce2015-08-12 12:21:00 +02005090
Radek Krejci010e54b2016-03-15 09:40:34 +01005091 /* HACK: when a grouping has uses inside, all such uses have to be resolved before the grouping itself
5092 * is used in some uses. When we see such a uses, the grouping's nacm member (not used in grouping)
5093 * is used to store number of so far unresolved uses. The grouping cannot be used unless the nacm
5094 * value is decreased back to 0. To remember that the uses already increased grouping's nacm, the
5095 * LYS_USESGRP flag is used. */
Michal Vaskodcf98e62016-05-05 17:53:53 +02005096 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 +02005097
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005098 if (!uses->grp) {
Michal Vasko3edeaf72016-02-11 13:17:43 +01005099 rc = resolve_uses_schema_nodeid(uses->name, (const struct lys_node *)uses, (const struct lys_node_grp **)&uses->grp);
5100 if (rc == -1) {
Michal Vasko92981a62016-10-14 10:25:16 +02005101 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005102 return -1;
5103 } else if (rc > 0) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005104 LOGVAL(LYE_INCHAR, LY_VLOG_LYS, uses, uses->name[rc - 1], &uses->name[rc - 1]);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005105 return -1;
5106 } else if (!uses->grp) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005107 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005108 /* hack - in contrast to lys_node, lys_node_grp has bigger nacm field
5109 * (and smaller flags - it uses only a limited set of flags)
5110 */
5111 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005112 uses->flags |= LYS_USESGRP;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005113 }
Michal Vasko92981a62016-10-14 10:25:16 +02005114 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3edeaf72016-02-11 13:17:43 +01005115 return EXIT_FAILURE;
Michal Vasko12e30842015-08-04 11:54:00 +02005116 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005117 }
5118
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005119 if (uses->grp->nacm) {
Radek Krejci010e54b2016-03-15 09:40:34 +01005120 if (par_grp && !(uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005121 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci010e54b2016-03-15 09:40:34 +01005122 uses->flags |= LYS_USESGRP;
Radek Krejcie00d2312016-08-12 15:27:49 +02005123 } else {
5124 /* instantiate grouping only when it is completely resolved */
5125 uses->grp = NULL;
Michal Vasko407f1bb2015-09-23 15:51:07 +02005126 }
Michal Vasko92981a62016-10-14 10:25:16 +02005127 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, uses, "uses", uses->name);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005128 return EXIT_FAILURE;
5129 }
5130
Radek Krejci48464ed2016-03-17 15:44:09 +01005131 rc = resolve_uses(uses, unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005132 if (!rc) {
5133 /* decrease unres count only if not first try */
Radek Krejci010e54b2016-03-15 09:40:34 +01005134 if (par_grp && (uses->flags & LYS_USESGRP)) {
Radek Krejci4372b4e2016-04-14 17:42:16 +02005135 if (!((struct lys_node_grp *)par_grp)->nacm) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005136 LOGINT;
5137 return -1;
5138 }
Radek Krejci4372b4e2016-04-14 17:42:16 +02005139 ((struct lys_node_grp *)par_grp)->nacm--;
Radek Krejci010e54b2016-03-15 09:40:34 +01005140 uses->flags &= ~LYS_USESGRP;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005141 }
Radek Krejcicf509982015-12-15 09:22:44 +01005142
5143 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005144 if (lyp_check_status(uses->flags, uses->module, "of uses",
Radek Krejciadb57612016-02-16 13:34:34 +01005145 uses->grp->flags, uses->grp->module, uses->grp->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005146 (struct lys_node *)uses)) {
Radek Krejcicf509982015-12-15 09:22:44 +01005147 return -1;
5148 }
5149
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005150 return EXIT_SUCCESS;
5151 }
5152
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005153 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005154}
5155
Michal Vasko730dfdf2015-08-11 14:48:05 +02005156/**
Michal Vasko9957e592015-08-17 15:04:09 +02005157 * @brief Resolve list keys. Logs directly.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005158 *
Michal Vaskobb211122015-08-19 14:03:11 +02005159 * @param[in] list List to use.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005160 * @param[in] keys_str Keys node value.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005161 *
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005162 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
Michal Vasko730dfdf2015-08-11 14:48:05 +02005163 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005164static int
Radek Krejci48464ed2016-03-17 15:44:09 +01005165resolve_list_keys(struct lys_node_list *list, const char *keys_str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005166{
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005167 int i, len, rc;
Michal Vasko4f0dad02016-02-15 14:08:23 +01005168 const char *value;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005169
5170 for (i = 0; i < list->keys_size; ++i) {
5171 /* get the key name */
5172 if ((value = strpbrk(keys_str, " \t\n"))) {
5173 len = value - keys_str;
5174 while (isspace(value[0])) {
5175 value++;
5176 }
5177 } else {
5178 len = strlen(keys_str);
5179 }
5180
Radek Krejcic4283442016-04-22 09:19:27 +02005181 rc = lys_get_sibling(list->child, lys_main_module(list->module)->name, 0, keys_str, len, LYS_LEAF, (const struct lys_node **)&list->keys[i]);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005182 if (rc) {
Michal Vasko7a55bea2016-05-02 14:51:20 +02005183 LOGVAL(LYE_INRESOLV, LY_VLOG_LYS, list, "list keys", keys_str);
5184 return EXIT_FAILURE;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005185 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005186
Radek Krejci48464ed2016-03-17 15:44:09 +01005187 if (check_key(list, i, keys_str, len)) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005188 /* check_key logs */
5189 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005190 }
5191
Radek Krejcicf509982015-12-15 09:22:44 +01005192 /* check status */
Radek Krejcic6556022016-01-27 15:16:45 +01005193 if (lyp_check_status(list->flags, list->module, list->name,
Radek Krejci48464ed2016-03-17 15:44:09 +01005194 list->keys[i]->flags, list->keys[i]->module, list->keys[i]->name,
5195 (struct lys_node *)list->keys[i])) {
Radek Krejcicf509982015-12-15 09:22:44 +01005196 return -1;
5197 }
5198
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005199 /* prepare for next iteration */
5200 while (value && isspace(value[0])) {
5201 value++;
5202 }
5203 keys_str = value;
5204 }
5205
Michal Vaskof02e3742015-08-05 16:27:02 +02005206 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005207}
5208
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005209/**
Michal Vaskobf19d252015-10-08 15:39:17 +02005210 * @brief Resolve (check) all must conditions of \p node.
5211 * Logs directly.
5212 *
5213 * @param[in] node Data node with optional must statements.
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005214 * @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 +02005215 *
5216 * @return EXIT_SUCCESS on pass, EXIT_FAILURE on fail, -1 on error.
5217 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005218static int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005219resolve_must(struct lyd_node *node, int inout_parent)
Michal Vaskof02e3742015-08-05 16:27:02 +02005220{
Michal Vaskobf19d252015-10-08 15:39:17 +02005221 uint8_t i, must_size;
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005222 struct lys_node *schema;
Michal Vaskobf19d252015-10-08 15:39:17 +02005223 struct lys_restr *must;
5224 struct lyxp_set set;
5225
5226 assert(node);
5227 memset(&set, 0, sizeof set);
5228
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005229 if (inout_parent) {
5230 for (schema = lys_parent(node->schema);
5231 schema && (schema->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES));
5232 schema = lys_parent(schema));
5233 if (!schema || !(schema->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5234 LOGINT;
5235 return -1;
5236 }
5237 must_size = ((struct lys_node_inout *)schema)->must_size;
5238 must = ((struct lys_node_inout *)schema)->must;
5239
5240 /* context node is the RPC/action */
5241 node = node->parent;
5242 if (!(node->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
5243 LOGINT;
5244 return -1;
5245 }
5246 } else {
5247 switch (node->schema->nodetype) {
5248 case LYS_CONTAINER:
5249 must_size = ((struct lys_node_container *)node->schema)->must_size;
5250 must = ((struct lys_node_container *)node->schema)->must;
5251 break;
5252 case LYS_LEAF:
5253 must_size = ((struct lys_node_leaf *)node->schema)->must_size;
5254 must = ((struct lys_node_leaf *)node->schema)->must;
5255 break;
5256 case LYS_LEAFLIST:
5257 must_size = ((struct lys_node_leaflist *)node->schema)->must_size;
5258 must = ((struct lys_node_leaflist *)node->schema)->must;
5259 break;
5260 case LYS_LIST:
5261 must_size = ((struct lys_node_list *)node->schema)->must_size;
5262 must = ((struct lys_node_list *)node->schema)->must;
5263 break;
5264 case LYS_ANYXML:
5265 case LYS_ANYDATA:
5266 must_size = ((struct lys_node_anydata *)node->schema)->must_size;
5267 must = ((struct lys_node_anydata *)node->schema)->must;
5268 break;
5269 case LYS_NOTIF:
5270 must_size = ((struct lys_node_notif *)node->schema)->must_size;
5271 must = ((struct lys_node_notif *)node->schema)->must;
5272 break;
5273 default:
5274 must_size = 0;
5275 break;
5276 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005277 }
5278
5279 for (i = 0; i < must_size; ++i) {
Michal Vaskoa59495d2016-08-22 09:18:58 +02005280 if (lyxp_eval(must[i].expr, node, LYXP_NODE_ELEM, &set, LYXP_MUST)) {
Michal Vaskobf19d252015-10-08 15:39:17 +02005281 return -1;
5282 }
5283
Michal Vasko944a5642016-03-21 11:48:58 +01005284 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_MUST);
Michal Vaskobf19d252015-10-08 15:39:17 +02005285
Michal Vasko8146d4c2016-05-09 15:50:29 +02005286 if (!set.val.bool) {
Michal Vasko6ac68282016-04-11 10:56:47 +02005287 LOGVAL(LYE_NOMUST, LY_VLOG_LYD, node, must[i].expr);
5288 if (must[i].emsg) {
5289 LOGVAL(LYE_SPEC, LY_VLOG_LYD, node, must[i].emsg);
5290 }
5291 if (must[i].eapptag) {
5292 strncpy(((struct ly_err *)&ly_errno)->apptag, must[i].eapptag, LY_APPTAG_LEN - 1);
5293 }
Michal Vaskobf19d252015-10-08 15:39:17 +02005294 return 1;
5295 }
5296 }
5297
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005298 return EXIT_SUCCESS;
Michal Vaskof02e3742015-08-05 16:27:02 +02005299}
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005300
Michal Vaskobf19d252015-10-08 15:39:17 +02005301/**
Michal Vasko508a50d2016-09-07 14:50:33 +02005302 * @brief Resolve (find) when condition schema context node. Does not log.
5303 *
5304 * @param[in] schema Schema node with the when condition.
5305 * @param[out] ctx_snode When schema context node.
5306 * @param[out] ctx_snode_type Schema context node type.
5307 */
5308void
5309resolve_when_ctx_snode(const struct lys_node *schema, struct lys_node **ctx_snode, enum lyxp_node_type *ctx_snode_type)
5310{
5311 const struct lys_node *sparent;
5312
5313 /* find a not schema-only node */
5314 *ctx_snode_type = LYXP_NODE_ELEM;
5315 while (schema->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE | LYS_AUGMENT | LYS_INPUT | LYS_OUTPUT)) {
5316 if (schema->nodetype == LYS_AUGMENT) {
5317 sparent = ((struct lys_node_augment *)schema)->target;
5318 } else {
5319 sparent = schema->parent;
5320 }
5321 if (!sparent) {
5322 /* context node is the document root (fake root in our case) */
5323 if (schema->flags & LYS_CONFIG_W) {
5324 *ctx_snode_type = LYXP_NODE_ROOT_CONFIG;
5325 } else {
Michal Vaskob94a5e42016-09-08 14:01:56 +02005326 *ctx_snode_type = LYXP_NODE_ROOT;
Michal Vasko508a50d2016-09-07 14:50:33 +02005327 }
Michal Vasko2d2aec12016-09-08 11:42:50 +02005328 /* we need the first top-level sibling, but no uses or groupings */
Michal Vaskob94a5e42016-09-08 14:01:56 +02005329 schema = lys_getnext(NULL, NULL, lys_node_module(schema), 0);
Michal Vasko508a50d2016-09-07 14:50:33 +02005330 break;
5331 }
5332 schema = sparent;
5333 }
5334
5335 *ctx_snode = (struct lys_node *)schema;
5336}
5337
5338/**
Michal Vaskocf024702015-10-08 15:01:42 +02005339 * @brief Resolve (find) when condition context node. Does not log.
5340 *
5341 * @param[in] node Data node, whose conditional definition is being decided.
Michal Vasko508a50d2016-09-07 14:50:33 +02005342 * @param[in] schema Schema node with the when condition.
Michal Vaskoa59495d2016-08-22 09:18:58 +02005343 * @param[out] ctx_node Context node.
5344 * @param[out] ctx_node_type Context node type.
Michal Vaskocf024702015-10-08 15:01:42 +02005345 *
Michal Vaskoa59495d2016-08-22 09:18:58 +02005346 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vaskocf024702015-10-08 15:01:42 +02005347 */
Michal Vaskoa59495d2016-08-22 09:18:58 +02005348static int
5349resolve_when_ctx_node(struct lyd_node *node, struct lys_node *schema, struct lyd_node **ctx_node,
5350 enum lyxp_node_type *ctx_node_type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005351{
Michal Vaskocf024702015-10-08 15:01:42 +02005352 struct lyd_node *parent;
5353 struct lys_node *sparent;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005354 enum lyxp_node_type node_type;
Michal Vaskocf024702015-10-08 15:01:42 +02005355 uint16_t i, data_depth, schema_depth;
5356
Michal Vasko508a50d2016-09-07 14:50:33 +02005357 resolve_when_ctx_snode(schema, &schema, &node_type);
Michal Vaskocf024702015-10-08 15:01:42 +02005358
Michal Vaskofe989752016-09-08 08:47:26 +02005359 if (node_type == LYXP_NODE_ELEM) {
5360 /* standard element context node */
5361 for (parent = node, data_depth = 0; parent; parent = parent->parent, ++data_depth);
5362 for (sparent = schema, schema_depth = 0;
5363 sparent;
5364 sparent = (sparent->nodetype == LYS_AUGMENT ? ((struct lys_node_augment *)sparent)->target : sparent->parent)) {
5365 if (sparent->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_LEAFLIST | LYS_LIST | LYS_ANYDATA | LYS_NOTIF | LYS_RPC)) {
5366 ++schema_depth;
5367 }
Michal Vaskocf024702015-10-08 15:01:42 +02005368 }
Michal Vaskofe989752016-09-08 08:47:26 +02005369 if (data_depth < schema_depth) {
5370 return -1;
5371 }
Michal Vaskocf024702015-10-08 15:01:42 +02005372
Michal Vasko956e8542016-08-26 09:43:35 +02005373 /* find the corresponding data node */
5374 for (i = 0; i < data_depth - schema_depth; ++i) {
5375 node = node->parent;
5376 }
Michal Vaskoa59495d2016-08-22 09:18:58 +02005377 if (node->schema != schema) {
5378 return -1;
5379 }
Michal Vaskofe989752016-09-08 08:47:26 +02005380 } else {
5381 /* root context node */
5382 while (node->parent) {
5383 node = node->parent;
5384 }
5385 while (node->prev->next) {
5386 node = node->prev;
5387 }
Michal Vaskocf024702015-10-08 15:01:42 +02005388 }
5389
Michal Vaskoa59495d2016-08-22 09:18:58 +02005390 *ctx_node = node;
5391 *ctx_node_type = node_type;
5392 return EXIT_SUCCESS;
Michal Vaskocf024702015-10-08 15:01:42 +02005393}
5394
Michal Vasko76c3bd32016-08-24 16:02:52 +02005395/**
5396 * @brief Temporarily unlink nodes as per YANG 1.1 RFC section 7.21.5 for when XPath evaluation.
5397 * The context nodes is adjusted if needed.
5398 *
5399 * @param[in] snode Schema node, whose children instances need to be unlinked.
5400 * @param[in,out] node Data siblings where to look for the children of \p snode. If it is unlinked,
5401 * it is moved to point to another sibling still in the original tree.
5402 * @param[in,out] ctx_node When context node, adjusted if needed.
5403 * @param[in] ctx_node_type Context node type, just for information to detect invalid situations.
5404 * @param[out] unlinked_nodes Unlinked siblings. Can be safely appended to \p node afterwards.
5405 * Ordering may change, but there will be no semantic change.
5406 *
5407 * @return EXIT_SUCCESS on success, -1 on error.
5408 */
5409static int
5410resolve_when_unlink_nodes(struct lys_node *snode, struct lyd_node **node, struct lyd_node **ctx_node,
5411 enum lyxp_node_type ctx_node_type, struct lyd_node **unlinked_nodes)
5412{
5413 struct lyd_node *next, *elem;
5414
5415 switch (snode->nodetype) {
5416 case LYS_AUGMENT:
5417 case LYS_USES:
5418 case LYS_CHOICE:
5419 case LYS_CASE:
5420 LY_TREE_FOR(snode->child, snode) {
5421 if (resolve_when_unlink_nodes(snode, node, ctx_node, ctx_node_type, unlinked_nodes)) {
5422 return -1;
5423 }
5424 }
5425 break;
5426 case LYS_CONTAINER:
5427 case LYS_LIST:
5428 case LYS_LEAF:
5429 case LYS_LEAFLIST:
5430 case LYS_ANYXML:
5431 case LYS_ANYDATA:
5432 LY_TREE_FOR_SAFE(lyd_first_sibling(*node), next, elem) {
5433 if (elem->schema == snode) {
5434
5435 if (elem == *ctx_node) {
5436 /* We are going to unlink our context node! This normally cannot happen,
5437 * but we use normal top-level data nodes for faking a document root node,
5438 * so if this is the context node, we just use the next top-level node.
5439 * Additionally, it can even happen that there are no top-level data nodes left,
5440 * all were unlinked, so in this case we pass NULL as the context node/data tree,
5441 * lyxp_eval() can handle this special situation.
5442 */
5443 if (ctx_node_type == LYXP_NODE_ELEM) {
5444 LOGINT;
5445 return -1;
5446 }
5447
5448 if (elem->prev == elem) {
5449 /* unlinking last top-level element, use an empty data tree */
5450 *ctx_node = NULL;
5451 } else {
5452 /* in this case just use the previous/last top-level data node */
5453 *ctx_node = elem->prev;
5454 }
5455 } else if (elem == *node) {
5456 /* We are going to unlink the currently processed node. This does not matter that
5457 * much, but we would lose access to the original data tree, so just move our
5458 * pointer somewhere still inside it.
5459 */
5460 if ((*node)->prev != *node) {
5461 *node = (*node)->prev;
5462 } else {
5463 /* the processed node with sibings were all unlinked, oh well */
5464 *node = NULL;
5465 }
5466 }
5467
5468 /* temporarily unlink the node */
5469 lyd_unlink(elem);
5470 if (*unlinked_nodes) {
5471 if (lyd_insert_after(*unlinked_nodes, elem)) {
5472 LOGINT;
5473 return -1;
5474 }
5475 } else {
5476 *unlinked_nodes = elem;
5477 }
5478
5479 if (snode->nodetype & (LYS_CONTAINER | LYS_LEAF | LYS_ANYDATA)) {
5480 /* there can be only one instance */
5481 break;
5482 }
5483 }
5484 }
5485 break;
5486 default:
5487 LOGINT;
5488 return -1;
5489 }
5490
5491 return EXIT_SUCCESS;
5492}
5493
5494/**
5495 * @brief Relink the unlinked nodes back.
5496 *
5497 * @param[in] node Data node to link the nodes back to. It can actually be the adjusted context node,
5498 * we simply need a sibling from the original data tree.
5499 * @param[in] unlinked_nodes Unlinked nodes to relink to \p node.
5500 * @param[in] ctx_node_type Context node type to distinguish between \p node being the parent
5501 * or the sibling of \p unlinked_nodes.
5502 *
5503 * @return EXIT_SUCCESS on success, -1 on error.
5504 */
5505static int
5506resolve_when_relink_nodes(struct lyd_node *node, struct lyd_node *unlinked_nodes, enum lyxp_node_type ctx_node_type)
5507{
5508 struct lyd_node *elem;
5509
5510 LY_TREE_FOR_SAFE(unlinked_nodes, unlinked_nodes, elem) {
5511 if (ctx_node_type == LYXP_NODE_ELEM) {
5512 if (lyd_insert(node, elem)) {
5513 return -1;
5514 }
5515 } else {
5516 if (lyd_insert_after(node, elem)) {
5517 return -1;
5518 }
5519 }
5520 }
5521
5522 return EXIT_SUCCESS;
5523}
5524
Radek Krejci03b71f72016-03-16 11:10:09 +01005525int
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005526resolve_applies_must(const struct lyd_node *node)
Radek Krejci01696bf2016-03-18 13:19:36 +01005527{
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005528 int ret = 0;
5529 uint8_t must_size;
5530 struct lys_node *schema, *iter;
Radek Krejci46165822016-08-26 14:06:27 +02005531
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005532 assert(node);
5533
5534 schema = node->schema;
5535
5536 /* their own must */
Radek Krejci46165822016-08-26 14:06:27 +02005537 switch (schema->nodetype) {
Radek Krejci01696bf2016-03-18 13:19:36 +01005538 case LYS_CONTAINER:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005539 must_size = ((struct lys_node_container *)schema)->must_size;
5540 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005541 case LYS_LEAF:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005542 must_size = ((struct lys_node_leaf *)schema)->must_size;
5543 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005544 case LYS_LEAFLIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005545 must_size = ((struct lys_node_leaflist *)schema)->must_size;
5546 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005547 case LYS_LIST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005548 must_size = ((struct lys_node_list *)schema)->must_size;
5549 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005550 case LYS_ANYXML:
Radek Krejcibf2abff2016-08-23 15:51:52 +02005551 case LYS_ANYDATA:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005552 must_size = ((struct lys_node_anydata *)schema)->must_size;
5553 break;
5554 case LYS_NOTIF:
5555 must_size = ((struct lys_node_notif *)schema)->must_size;
5556 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005557 default:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005558 must_size = 0;
5559 break;
Radek Krejci01696bf2016-03-18 13:19:36 +01005560 }
Michal Vaskoc8c810c2016-09-15 14:02:00 +02005561
5562 if (must_size) {
5563 ++ret;
5564 }
5565
5566 /* schema may be a direct data child of input/output with must (but it must be first, it needs to be evaluated only once) */
5567 if (!node->prev->next) {
5568 for (iter = lys_parent(schema); iter && (iter->nodetype & (LYS_CHOICE | LYS_CASE | LYS_USES)); iter = lys_parent(iter));
5569 if (iter && (iter->nodetype & (LYS_INPUT | LYS_OUTPUT))) {
5570 ret += 0x2;
5571 }
5572 }
5573
5574 return ret;
Radek Krejci01696bf2016-03-18 13:19:36 +01005575}
5576
5577int
Radek Krejci46165822016-08-26 14:06:27 +02005578resolve_applies_when(const struct lys_node *schema, int mode, const struct lys_node *stop)
Radek Krejci03b71f72016-03-16 11:10:09 +01005579{
Radek Krejci46165822016-08-26 14:06:27 +02005580 const struct lys_node *parent;
Radek Krejci03b71f72016-03-16 11:10:09 +01005581
Radek Krejci46165822016-08-26 14:06:27 +02005582 assert(schema);
Radek Krejci03b71f72016-03-16 11:10:09 +01005583
Radek Krejci46165822016-08-26 14:06:27 +02005584 if (!(schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)schema)->when)) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005585 return 1;
5586 }
5587
Radek Krejci46165822016-08-26 14:06:27 +02005588 parent = schema;
Radek Krejci03b71f72016-03-16 11:10:09 +01005589 goto check_augment;
5590
Radek Krejci46165822016-08-26 14:06:27 +02005591 while (parent) {
5592 /* stop conditions */
5593 if (!mode) {
5594 /* stop on node that can be instantiated in data tree */
5595 if (!(parent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5596 break;
5597 }
5598 } else {
5599 /* stop on the specified node */
5600 if (parent == stop) {
5601 break;
5602 }
5603 }
5604
5605 if (((const struct lys_node_uses *)parent)->when) {
Radek Krejci03b71f72016-03-16 11:10:09 +01005606 return 1;
5607 }
5608check_augment:
5609
5610 if ((parent->parent && (parent->parent->nodetype == LYS_AUGMENT) &&
Radek Krejci46165822016-08-26 14:06:27 +02005611 (((const struct lys_node_augment *)parent->parent)->when))) {
Michal Vaskoe3655562016-08-24 15:56:17 +02005612 return 1;
Radek Krejci03b71f72016-03-16 11:10:09 +01005613 }
5614 parent = lys_parent(parent);
5615 }
5616
5617 return 0;
5618}
5619
Michal Vaskocf024702015-10-08 15:01:42 +02005620/**
5621 * @brief Resolve (check) all when conditions relevant for \p node.
5622 * Logs directly.
5623 *
5624 * @param[in] node Data node, whose conditional reference, if such, is being decided.
Michal Vaskocf024702015-10-08 15:01:42 +02005625 *
Radek Krejci03b71f72016-03-16 11:10:09 +01005626 * @return
5627 * -1 - error, ly_errno is set
5628 * 0 - true "when" statement
Radek Krejci46165822016-08-26 14:06:27 +02005629 * 0, ly_vecode = LYVE_NOWHEN - false "when" statement
Radek Krejci03b71f72016-03-16 11:10:09 +01005630 * 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 +02005631 */
Radek Krejci46165822016-08-26 14:06:27 +02005632int
5633resolve_when(struct lyd_node *node, int *result)
Michal Vaskocf024702015-10-08 15:01:42 +02005634{
Michal Vasko76c3bd32016-08-24 16:02:52 +02005635 struct lyd_node *ctx_node = NULL, *unlinked_nodes, *tmp_node;
Michal Vasko90fc2a32016-08-24 15:58:58 +02005636 struct lys_node *sparent;
Michal Vaskocf024702015-10-08 15:01:42 +02005637 struct lyxp_set set;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005638 enum lyxp_node_type ctx_node_type;
Radek Krejci51093642016-03-29 10:14:59 +02005639 int rc = 0;
Michal Vaskocf024702015-10-08 15:01:42 +02005640
5641 assert(node);
5642 memset(&set, 0, sizeof set);
5643
5644 if (!(node->schema->nodetype & (LYS_NOTIF | LYS_RPC)) && (((struct lys_node_container *)node->schema)->when)) {
Michal Vasko76c3bd32016-08-24 16:02:52 +02005645 /* make the node dummy for the evaluation */
5646 node->validity |= LYD_VAL_INUSE;
Michal Vaskoa59495d2016-08-22 09:18:58 +02005647 rc = lyxp_eval(((struct lys_node_container *)node->schema)->when->cond, node, LYXP_NODE_ELEM, &set, LYXP_WHEN);
Michal Vasko76c3bd32016-08-24 16:02:52 +02005648 node->validity &= ~LYD_VAL_INUSE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005649 if (rc) {
5650 if (rc == 1) {
Radek Krejci48464ed2016-03-17 15:44:09 +01005651 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005652 }
Radek Krejci51093642016-03-29 10:14:59 +02005653 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005654 }
5655
Radek Krejci03b71f72016-03-16 11:10:09 +01005656 /* set boolean result of the condition */
Michal Vasko944a5642016-03-21 11:48:58 +01005657 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005658 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005659 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_container *)node->schema)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005660 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005661 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005662 }
Radek Krejci51093642016-03-29 10:14:59 +02005663
5664 /* free xpath set content */
5665 lyxp_set_cast(&set, LYXP_SET_EMPTY, node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005666 }
5667
Michal Vasko90fc2a32016-08-24 15:58:58 +02005668 sparent = node->schema;
Michal Vaskocf024702015-10-08 15:01:42 +02005669 goto check_augment;
5670
5671 /* check when in every schema node that affects node */
Michal Vasko90fc2a32016-08-24 15:58:58 +02005672 while (sparent && (sparent->nodetype & (LYS_USES | LYS_CHOICE | LYS_CASE))) {
5673 if (((struct lys_node_uses *)sparent)->when) {
Michal Vaskocf024702015-10-08 15:01:42 +02005674 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005675 rc = resolve_when_ctx_node(node, sparent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005676 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005677 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005678 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005679 }
5680 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005681
5682 unlinked_nodes = NULL;
5683 /* we do not want our node pointer to change */
5684 tmp_node = node;
5685 rc = resolve_when_unlink_nodes(sparent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5686 if (rc) {
5687 goto cleanup;
5688 }
5689
5690 rc = lyxp_eval(((struct lys_node_uses *)sparent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5691
5692 if (unlinked_nodes && ctx_node) {
5693 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5694 rc = -1;
5695 goto cleanup;
5696 }
5697 }
5698
Radek Krejci03b71f72016-03-16 11:10:09 +01005699 if (rc) {
5700 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005701 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005702 }
Radek Krejci51093642016-03-29 10:14:59 +02005703 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005704 }
5705
Michal Vasko944a5642016-03-21 11:48:58 +01005706 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vasko8146d4c2016-05-09 15:50:29 +02005707 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005708 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_uses *)sparent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005709 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005710 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005711 }
Radek Krejci51093642016-03-29 10:14:59 +02005712
5713 /* free xpath set content */
5714 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005715 }
5716
5717check_augment:
Michal Vasko90fc2a32016-08-24 15:58:58 +02005718 if ((sparent->parent && (sparent->parent->nodetype == LYS_AUGMENT) && (((struct lys_node_augment *)sparent->parent)->when))) {
Michal Vaskocf024702015-10-08 15:01:42 +02005719 if (!ctx_node) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005720 rc = resolve_when_ctx_node(node, sparent->parent, &ctx_node, &ctx_node_type);
Michal Vaskoa59495d2016-08-22 09:18:58 +02005721 if (rc) {
Michal Vaskocf024702015-10-08 15:01:42 +02005722 LOGINT;
Radek Krejci51093642016-03-29 10:14:59 +02005723 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005724 }
5725 }
Michal Vasko76c3bd32016-08-24 16:02:52 +02005726
5727 unlinked_nodes = NULL;
5728 tmp_node = node;
5729 rc = resolve_when_unlink_nodes(sparent->parent, &tmp_node, &ctx_node, ctx_node_type, &unlinked_nodes);
5730 if (rc) {
5731 goto cleanup;
5732 }
5733
5734 rc = lyxp_eval(((struct lys_node_augment *)sparent->parent)->when->cond, ctx_node, ctx_node_type, &set, LYXP_WHEN);
5735
5736 /* reconnect nodes, if ctx_node is NULL then all the nodes were unlinked, but linked together,
5737 * so the tree did not actually change and there is nothing for us to do
5738 */
5739 if (unlinked_nodes && ctx_node) {
5740 if (resolve_when_relink_nodes(ctx_node, unlinked_nodes, ctx_node_type)) {
5741 rc = -1;
5742 goto cleanup;
5743 }
5744 }
5745
Radek Krejci03b71f72016-03-16 11:10:09 +01005746 if (rc) {
5747 if (rc == 1) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005748 LOGVAL(LYE_INWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci03b71f72016-03-16 11:10:09 +01005749 }
Radek Krejci51093642016-03-29 10:14:59 +02005750 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005751 }
5752
Michal Vasko944a5642016-03-21 11:48:58 +01005753 lyxp_set_cast(&set, LYXP_SET_BOOLEAN, ctx_node, LYXP_WHEN);
Michal Vaskocf024702015-10-08 15:01:42 +02005754
Michal Vasko8146d4c2016-05-09 15:50:29 +02005755 if (!set.val.bool) {
Michal Vasko90fc2a32016-08-24 15:58:58 +02005756 LOGVAL(LYE_NOWHEN, LY_VLOG_LYD, node, ((struct lys_node_augment *)sparent->parent)->when->cond);
Radek Krejci0b7704f2016-03-18 12:16:14 +01005757 node->when_status |= LYD_WHEN_FALSE;
Radek Krejci51093642016-03-29 10:14:59 +02005758 goto cleanup;
Michal Vaskocf024702015-10-08 15:01:42 +02005759 }
Radek Krejci51093642016-03-29 10:14:59 +02005760
5761 /* free xpath set content */
5762 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node, 0);
Michal Vaskocf024702015-10-08 15:01:42 +02005763 }
5764
Michal Vasko90fc2a32016-08-24 15:58:58 +02005765 sparent = lys_parent(sparent);
Michal Vaskocf024702015-10-08 15:01:42 +02005766 }
5767
Radek Krejci0b7704f2016-03-18 12:16:14 +01005768 node->when_status |= LYD_WHEN_TRUE;
Radek Krejci03b71f72016-03-16 11:10:09 +01005769
Radek Krejci51093642016-03-29 10:14:59 +02005770cleanup:
Radek Krejci51093642016-03-29 10:14:59 +02005771 /* free xpath set content */
5772 lyxp_set_cast(&set, LYXP_SET_EMPTY, ctx_node ? ctx_node : node, 0);
5773
Radek Krejci46165822016-08-26 14:06:27 +02005774 if (result) {
5775 if (node->when_status & LYD_WHEN_TRUE) {
5776 *result = 1;
5777 } else {
5778 *result = 0;
5779 }
5780 }
5781
Radek Krejci51093642016-03-29 10:14:59 +02005782 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005783}
5784
Radek Krejcicbb473e2016-09-16 14:48:32 +02005785static int
5786check_leafref_features(struct lys_type *type)
5787{
5788 struct lys_node *iter;
5789 struct ly_set *src_parents, *trg_parents, *features;
5790 unsigned int i, j, size, x;
5791 int ret = EXIT_SUCCESS;
5792
5793 assert(type->parent);
5794
5795 src_parents = ly_set_new();
5796 trg_parents = ly_set_new();
5797 features = ly_set_new();
5798
5799 /* get parents chain of source (leafref) */
5800 for (iter = (struct lys_node *)type->parent; iter; iter = iter->parent) {
5801 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5802 continue;
5803 }
5804 ly_set_add(src_parents, iter, LY_SET_OPT_USEASLIST);
5805 }
5806 /* get parents chain of target */
5807 for (iter = (struct lys_node *)type->info.lref.target; iter; iter = iter->parent) {
5808 if (iter->nodetype & (LYS_INPUT | LYS_OUTPUT)) {
5809 continue;
5810 }
5811 ly_set_add(trg_parents, iter, LY_SET_OPT_USEASLIST);
5812 }
5813
5814 /* compare the features used in if-feature statements in the rest of both
5815 * chains of parents. The set of features used for target must be a subset
5816 * of features used for the leafref. This is not a perfect, we should compare
5817 * the truth tables but it could require too much resources, so we simplify that */
5818 for (i = 0; i < src_parents->number; i++) {
5819 iter = src_parents->set.s[i]; /* shortcut */
5820 if (!iter->iffeature_size) {
5821 continue;
5822 }
5823 for (j = 0; j < iter->iffeature_size; j++) {
5824 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5825 for (; size; size--) {
5826 if (!iter->iffeature[j].features[size - 1]) {
5827 /* not yet resolved feature, postpone this check */
5828 ret = EXIT_FAILURE;
5829 goto cleanup;
5830 }
5831 ly_set_add(features, iter->iffeature[j].features[size - 1], 0);
5832 }
5833 }
5834 }
5835 x = features->number;
5836 for (i = 0; i < trg_parents->number; i++) {
5837 iter = trg_parents->set.s[i]; /* shortcut */
5838 if (!iter->iffeature_size) {
5839 continue;
5840 }
5841 for (j = 0; j < iter->iffeature_size; j++) {
5842 resolve_iffeature_getsizes(&iter->iffeature[j], NULL, &size);
5843 for (; size; size--) {
5844 if (!iter->iffeature[j].features[size - 1]) {
5845 /* not yet resolved feature, postpone this check */
5846 ret = EXIT_FAILURE;
5847 goto cleanup;
5848 }
5849 if ((unsigned int)ly_set_add(features, iter->iffeature[j].features[size - 1], 0) >= x) {
5850 /* the feature is not present in features set of target's parents chain */
5851 LOGVAL(LYE_NORESOLV, LY_VLOG_LYS, type->parent, "leafref", type->info.lref.path);
5852 LOGVAL(LYE_SPEC, LY_VLOG_LYS, type->parent,
5853 "Leafref is not conditional based on \"%s\" feature as its target.",
5854 iter->iffeature[j].features[size - 1]->name);
5855 ret = -1;
5856 goto cleanup;
5857 }
5858 }
5859 }
5860 }
5861
5862cleanup:
5863 ly_set_free(features);
5864 ly_set_free(src_parents);
5865 ly_set_free(trg_parents);
5866
5867 return ret;
5868}
5869
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005870/**
Michal Vaskobb211122015-08-19 14:03:11 +02005871 * @brief Resolve a single unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005872 *
5873 * @param[in] mod Main module.
5874 * @param[in] item Item to resolve. Type determined by \p type.
5875 * @param[in] type Type of the unresolved item.
5876 * @param[in] str_snode String, a schema node, or NULL.
Michal Vaskobb211122015-08-19 14:03:11 +02005877 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02005878 *
5879 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
5880 */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005881static int
Michal Vasko0bd29d12015-08-19 11:45:49 +02005882resolve_unres_schema_item(struct lys_module *mod, void *item, enum UNRES_ITEM type, void *str_snode,
Radek Krejci48464ed2016-03-17 15:44:09 +01005883 struct unres_schema *unres)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005884{
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005885 /* has_str - whether the str_snode is a string in a dictionary that needs to be freed */
Radek Krejcic79c6b12016-07-26 15:11:49 +02005886 int rc = -1, has_str = 0, tpdf_flag = 0, i, k;
5887 unsigned int j;
Radek Krejcic13db382016-08-16 10:52:42 +02005888 struct lys_node *node, *par_grp;
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005889 const char *expr;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005890
Radek Krejcic79c6b12016-07-26 15:11:49 +02005891 struct ly_set *refs, *procs;
5892 struct lys_feature *ref, *feat;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005893 struct lys_ident *ident;
5894 struct lys_type *stype;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005895 struct lys_node_choice *choic;
Michal Vasko88c29542015-11-27 14:57:53 +01005896 struct lyxml_elem *yin;
Pavol Vicana0e4e672016-02-24 12:20:04 +01005897 struct yang_type *yang;
Radek Krejcid09d1a52016-08-11 14:05:45 +02005898 struct unres_list_uniq *unique_info;
Radek Krejcicbb473e2016-09-16 14:48:32 +02005899 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005900
5901 switch (type) {
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005902 case UNRES_IDENT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005903 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005904 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005905 ident = item;
5906
Radek Krejci018f1f52016-08-03 16:01:20 +02005907 rc = resolve_base_ident(mod, ident, expr, "identity", NULL, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005908 break;
5909 case UNRES_TYPE_IDENTREF:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02005910 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01005911 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005912 stype = item;
5913
Radek Krejci018f1f52016-08-03 16:01:20 +02005914 rc = resolve_base_ident(mod, NULL, expr, "type", stype, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005915 break;
5916 case UNRES_TYPE_LEAFREF:
Michal Vasko563ef092015-09-04 13:17:23 +02005917 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005918 stype = item;
5919
Radek Krejci2f12f852016-01-08 12:59:57 +01005920 /* HACK - when there is no parent, we are in top level typedef and in that
5921 * case, the path has to contain absolute path, so we let the resolve_path_arg_schema()
5922 * know it via tpdf_flag */
5923 if (!node) {
Radek Krejci4f78b532016-02-17 13:43:00 +01005924 tpdf_flag = 1;
Radek Krejci2f12f852016-01-08 12:59:57 +01005925 node = (struct lys_node *)stype->parent;
5926 }
5927
Radek Krejci27fe55e2016-09-13 17:13:35 +02005928 if (!lys_node_module(node)->implemented) {
5929 /* not implemented module, don't bother with resolving the leafref
5930 * if the module is set to be implemented, tha path will be resolved then */
5931 rc = 0;
5932 break;
5933 }
Radek Krejci48464ed2016-03-17 15:44:09 +01005934 rc = resolve_path_arg_schema(stype->info.lref.path, node, tpdf_flag,
Michal Vasko1e62a092015-12-01 12:27:20 +01005935 (const struct lys_node **)&stype->info.lref.target);
Michal Vasko01c6fd22016-05-20 11:43:05 +02005936 if (!tpdf_flag && !rc) {
5937 assert(stype->info.lref.target);
Radek Krejcicbb473e2016-09-16 14:48:32 +02005938 /* check if leafref and its target are under a common if-features */
5939 rc = check_leafref_features(stype);
5940 if (rc) {
5941 break;
5942 }
5943
Radek Krejci46c4cd72016-01-21 15:13:52 +01005944 /* store the backlink from leafref target */
Michal Vasko01c6fd22016-05-20 11:43:05 +02005945 if (lys_leaf_add_leafref_target(stype->info.lref.target, (struct lys_node *)stype->parent)) {
5946 rc = -1;
Radek Krejci46c4cd72016-01-21 15:13:52 +01005947 }
Radek Krejci46c4cd72016-01-21 15:13:52 +01005948 }
5949
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005950 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005951 case UNRES_TYPE_DER_TPDF:
5952 tpdf_flag = 1;
5953 /* no break */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02005954 case UNRES_TYPE_DER:
Michal Vasko88c29542015-11-27 14:57:53 +01005955 /* parent */
5956 node = str_snode;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005957 stype = item;
5958
Michal Vasko88c29542015-11-27 14:57:53 +01005959 /* HACK type->der is temporarily unparsed type statement */
5960 yin = (struct lyxml_elem *)stype->der;
5961 stype->der = NULL;
5962
Pavol Vicana0e4e672016-02-24 12:20:04 +01005963 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
5964 yang = (struct yang_type *)yin;
Radek Krejci3a5501d2016-07-18 22:03:34 +02005965 rc = yang_check_type(mod, node, yang, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005966
5967 if (rc) {
Pavol Vican8bd72e42016-08-29 09:53:05 +02005968 /* may try again later */
5969 stype->der = (struct lys_tpdf *)yang;
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005970 } else {
5971 /* we need to always be able to free this, it's safe only in this case */
Pavol Vican5f0316a2016-04-05 21:21:11 +02005972 lydict_remove(mod->ctx, yang->name);
Pavol Vicand01d8ae2016-03-01 10:45:59 +01005973 free(yang);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005974 }
5975
Michal Vasko88c29542015-11-27 14:57:53 +01005976 } else {
Radek Krejci3a5501d2016-07-18 22:03:34 +02005977 rc = fill_yin_type(mod, node, yin, stype, tpdf_flag, unres);
Pavol Vicana0e4e672016-02-24 12:20:04 +01005978 if (!rc) {
5979 /* we need to always be able to free this, it's safe only in this case */
5980 lyxml_free(mod->ctx, yin);
5981 } else {
5982 /* may try again later, put all back how it was */
5983 stype->der = (struct lys_tpdf *)yin;
5984 }
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02005985 }
Radek Krejcic13db382016-08-16 10:52:42 +02005986 if (rc == EXIT_SUCCESS) {
Radek Krejci2c2fce82016-08-01 13:52:26 +02005987 /* it does not make sense to have leaf-list of empty type */
5988 if (!tpdf_flag && node->nodetype == LYS_LEAFLIST && stype->base == LY_TYPE_EMPTY) {
5989 LOGWRN("The leaf-list \"%s\" is of \"empty\" type, which does not make sense.", node->name);
5990 }
Radek Krejci9b6aad22016-09-20 15:55:51 +02005991 } else if (rc == EXIT_FAILURE && stype->base != LY_TYPE_ERR) {
Radek Krejcic13db382016-08-16 10:52:42 +02005992 /* forward reference - in case the type is in grouping, we have to make the grouping unusable
5993 * by uses statement until the type is resolved. We do that the same way as uses statements inside
5994 * grouping - the grouping's nacm member (not used un grouping) is used to increase the number of
5995 * so far unresolved items (uses and types). The grouping cannot be used unless the nacm value is 0.
Radek Krejci9b6aad22016-09-20 15:55:51 +02005996 * To remember that the grouping already increased grouping's nacm, the LY_TYPE_ERR is used as value
Radek Krejcic13db382016-08-16 10:52:42 +02005997 * of the type's base member. */
5998 for (par_grp = node; par_grp && (par_grp->nodetype != LYS_GROUPING); par_grp = lys_parent(par_grp));
5999 if (par_grp) {
6000 ((struct lys_node_grp *)par_grp)->nacm++;
Radek Krejci9b6aad22016-09-20 15:55:51 +02006001 stype->base = LY_TYPE_ERR;
Radek Krejcic13db382016-08-16 10:52:42 +02006002 }
Radek Krejci2c2fce82016-08-01 13:52:26 +02006003 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006004 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006005 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006006 iff_data = str_snode;
6007 rc = resolve_feature(iff_data->fname, strlen(iff_data->fname), iff_data->node, item);
Radek Krejci9ff0a922016-07-14 13:08:05 +02006008 if (!rc) {
6009 /* success */
Radek Krejcicbb473e2016-09-16 14:48:32 +02006010 lydict_remove(mod->ctx, iff_data->fname);
6011 free(iff_data);
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006012 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006013 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006014 case UNRES_FEATURE:
6015 feat = (struct lys_feature *)item;
6016
6017 if (feat->iffeature_size) {
6018 refs = ly_set_new();
6019 procs = ly_set_new();
6020 ly_set_add(procs, feat, 0);
6021
6022 while (procs->number) {
6023 ref = procs->set.g[procs->number - 1];
6024 ly_set_rm_index(procs, procs->number - 1);
6025
6026 for (i = 0; i < ref->iffeature_size; i++) {
6027 resolve_iffeature_getsizes(&ref->iffeature[i], NULL, &j);
6028 for (; j > 0 ; j--) {
Radek Krejcicbb473e2016-09-16 14:48:32 +02006029 if (ref->iffeature[i].features[j - 1]) {
Radek Krejcic79c6b12016-07-26 15:11:49 +02006030 if (ref->iffeature[i].features[j - 1] == feat) {
6031 LOGVAL(LYE_CIRC_FEATURES, LY_VLOG_NONE, NULL, feat->name);
6032 goto featurecheckdone;
6033 }
6034
6035 if (ref->iffeature[i].features[j - 1]->iffeature_size) {
6036 k = refs->number;
6037 if (ly_set_add(refs, ref->iffeature[i].features[j - 1], 0) == k) {
6038 /* not yet seen feature, add it for processing */
6039 ly_set_add(procs, ref->iffeature[i].features[j - 1], 0);
6040 }
6041 }
6042 } else {
6043 /* forward reference */
6044 rc = EXIT_FAILURE;
6045 goto featurecheckdone;
6046 }
6047 }
6048
6049 }
6050 }
6051 rc = EXIT_SUCCESS;
6052
6053featurecheckdone:
6054 ly_set_free(refs);
6055 ly_set_free(procs);
6056 }
6057
6058 break;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006059 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006060 rc = resolve_unres_schema_uses(item, unres);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006061 break;
6062 case UNRES_TYPE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006063 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006064 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006065 stype = item;
6066
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006067 rc = check_default(stype, expr, mod);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006068 break;
6069 case UNRES_CHOICE_DFLT:
Michal Vaskoc5c26b02016-06-29 11:10:29 +02006070 expr = str_snode;
Radek Krejci4f78b532016-02-17 13:43:00 +01006071 has_str = 1;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006072 choic = item;
6073
Radek Krejcie00d2312016-08-12 15:27:49 +02006074 if (!choic->dflt) {
6075 choic->dflt = resolve_choice_dflt(choic, expr);
6076 }
Michal Vasko7955b362015-09-04 14:18:15 +02006077 if (choic->dflt) {
Radek Krejcie00d2312016-08-12 15:27:49 +02006078 rc = lyp_check_mandatory_choice((struct lys_node *)choic);
Michal Vasko7955b362015-09-04 14:18:15 +02006079 } else {
6080 rc = EXIT_FAILURE;
Michal Vasko5fcfe7e2015-08-17 14:59:57 +02006081 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006082 break;
6083 case UNRES_LIST_KEYS:
Radek Krejci4f78b532016-02-17 13:43:00 +01006084 has_str = 1;
Radek Krejci48464ed2016-03-17 15:44:09 +01006085 rc = resolve_list_keys(item, str_snode);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006086 break;
6087 case UNRES_LIST_UNIQ:
Radek Krejcid09d1a52016-08-11 14:05:45 +02006088 unique_info = (struct unres_list_uniq *)item;
6089 rc = resolve_unique(unique_info->list, unique_info->expr, unique_info->trg_type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006090 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006091 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006092 rc = resolve_augment(item, NULL);
Michal Vasko7178e692016-02-12 15:58:05 +01006093 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006094 case UNRES_XPATH:
6095 node = (struct lys_node *)item;
Michal Vasko9e635ac2016-10-17 11:44:09 +02006096 rc = check_node_xpath(node);
Michal Vasko508a50d2016-09-07 14:50:33 +02006097 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006098 default:
6099 LOGINT;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006100 break;
6101 }
6102
Radek Krejci54081ce2016-08-12 15:21:47 +02006103 if (has_str && !rc) {
6104 /* the string is no more needed in case of success.
6105 * In case of forward reference, we will try to resolve the string later */
Radek Krejci4f78b532016-02-17 13:43:00 +01006106 lydict_remove(mod->ctx, str_snode);
6107 }
6108
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006109 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006110}
6111
Michal Vaskof02e3742015-08-05 16:27:02 +02006112/* logs directly */
6113static void
Radek Krejci48464ed2016-03-17 15:44:09 +01006114print_unres_schema_item_fail(void *item, enum UNRES_ITEM type, void *str_node)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006115{
Michal Vaskocb34dc62016-05-20 14:38:37 +02006116 struct lyxml_elem *xml;
6117 struct lyxml_attr *attr;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006118 struct unres_iffeat_data *iff_data;
Radek Krejci76e15e12016-06-22 11:02:24 +02006119 const char *type_name = NULL;
Michal Vaskocb34dc62016-05-20 14:38:37 +02006120
Michal Vaskof02e3742015-08-05 16:27:02 +02006121 switch (type) {
Michal Vaskof02e3742015-08-05 16:27:02 +02006122 case UNRES_IDENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006123 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identity", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006124 break;
6125 case UNRES_TYPE_IDENTREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006126 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "identityref", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006127 break;
6128 case UNRES_TYPE_LEAFREF:
Radek Krejci48464ed2016-03-17 15:44:09 +01006129 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "leafref",
6130 ((struct lys_type *)item)->info.lref.path);
Michal Vaskof02e3742015-08-05 16:27:02 +02006131 break;
Radek Krejci3a5501d2016-07-18 22:03:34 +02006132 case UNRES_TYPE_DER_TPDF:
Michal Vaskof02e3742015-08-05 16:27:02 +02006133 case UNRES_TYPE_DER:
Michal Vaskocb34dc62016-05-20 14:38:37 +02006134 xml = (struct lyxml_elem *)((struct lys_type *)item)->der;
6135 if (xml->flags & LY_YANG_STRUCTURE_FLAG) {
6136 type_name = ((struct yang_type *)xml)->name;
6137 } else {
6138 LY_TREE_FOR(xml->attr, attr) {
6139 if ((attr->type == LYXML_ATTR_STD) && !strcmp(attr->name, "name")) {
6140 type_name = attr->value;
6141 break;
6142 }
6143 }
6144 assert(attr);
6145 }
6146 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "derived type", type_name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006147 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006148 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006149 iff_data = str_node;
6150 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "if-feature", iff_data->fname);
Michal Vaskof02e3742015-08-05 16:27:02 +02006151 break;
Radek Krejcic79c6b12016-07-26 15:11:49 +02006152 case UNRES_FEATURE:
6153 LOGVRB("There are unresolved if-features for \"%s\" feature circular dependency check, it will be attempted later",
6154 ((struct lys_feature *)item)->name);
6155 break;
Michal Vaskof02e3742015-08-05 16:27:02 +02006156 case UNRES_USES:
Radek Krejci48464ed2016-03-17 15:44:09 +01006157 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "uses", ((struct lys_node_uses *)item)->name);
Michal Vaskof02e3742015-08-05 16:27:02 +02006158 break;
6159 case UNRES_TYPE_DFLT:
Radek Krejci2e2de832016-10-13 16:12:26 +02006160 if (str_node) {
6161 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "type default", (char *)str_node);
6162 } /* else no default value in the type itself, but we are checking some restrictions against
6163 * possible default value of some base type. The failure is caused by not resolved base type,
6164 * so it was already reported */
Michal Vaskof02e3742015-08-05 16:27:02 +02006165 break;
6166 case UNRES_CHOICE_DFLT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006167 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "choice default", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006168 break;
6169 case UNRES_LIST_KEYS:
Radek Krejci48464ed2016-03-17 15:44:09 +01006170 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list keys", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006171 break;
6172 case UNRES_LIST_UNIQ:
Radek Krejci48464ed2016-03-17 15:44:09 +01006173 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "list unique", (char *)str_node);
Michal Vaskof02e3742015-08-05 16:27:02 +02006174 break;
Michal Vasko7178e692016-02-12 15:58:05 +01006175 case UNRES_AUGMENT:
Radek Krejci48464ed2016-03-17 15:44:09 +01006176 LOGVRB("Resolving %s \"%s\" failed, it will be attempted later.", "augment target",
6177 ((struct lys_node_augment *)item)->target_name);
Michal Vasko7178e692016-02-12 15:58:05 +01006178 break;
Michal Vasko508a50d2016-09-07 14:50:33 +02006179 case UNRES_XPATH:
6180 LOGVRB("Resolving %s \"%s\" with the context node \"%s\" failed, it will be attempted later.", "XPath",
6181 (char *)str_node, ((struct lys_node *)item)->name);
6182 break;
Michal Vaskocf024702015-10-08 15:01:42 +02006183 default:
6184 LOGINT;
Michal Vaskof02e3742015-08-05 16:27:02 +02006185 break;
6186 }
6187}
6188
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006189/**
Michal Vaskobb211122015-08-19 14:03:11 +02006190 * @brief Resolve every unres schema item in the structure. Logs directly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006191 *
6192 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006193 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006194 *
Michal Vasko92b8a382015-08-19 14:03:49 +02006195 * @return EXIT_SUCCESS on success, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006196 */
Michal Vaskof02e3742015-08-05 16:27:02 +02006197int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006198resolve_unres_schema(struct lys_module *mod, struct unres_schema *unres)
Michal Vaskof02e3742015-08-05 16:27:02 +02006199{
Radek Krejci010e54b2016-03-15 09:40:34 +01006200 uint32_t i, resolved = 0, unres_count, res_count;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006201 int rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006202
6203 assert(unres);
6204
Michal Vaskoe8734262016-09-29 14:12:06 +02006205 LOGVRB("Resolving \"%s\" unresolved schema nodes and their constraints...", mod->name);
Radek Krejci010e54b2016-03-15 09:40:34 +01006206 ly_vlog_hide(1);
Michal Vasko51054ca2015-08-12 12:20:00 +02006207
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006208 /* uses */
Michal Vasko51054ca2015-08-12 12:20:00 +02006209 do {
Michal Vasko88c29542015-11-27 14:57:53 +01006210 unres_count = 0;
6211 res_count = 0;
Michal Vasko51054ca2015-08-12 12:20:00 +02006212
6213 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006214 /* UNRES_TYPE_LEAFREF must be resolved (for storing leafref target pointers);
Radek Krejcic79c6b12016-07-26 15:11:49 +02006215 * if-features are resolved here to make sure that we will have all if-features for
6216 * later check of feature circular dependency */
Radek Krejci018f1f52016-08-03 16:01:20 +02006217 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006218 continue;
6219 }
Radek Krejci018f1f52016-08-03 16:01:20 +02006220 /* processes UNRES_USES, UNRES_IFFEAT, UNRES_TYPE_DER, UNRES_TYPE_DER_TPDF, UNRES_TYPE_LEAFREF,
Radek Krejcie00d2312016-08-12 15:27:49 +02006221 * UNRES_CHOICE_DFLT and UNRES_IDENT */
Michal Vasko51054ca2015-08-12 12:20:00 +02006222
Michal Vasko88c29542015-11-27 14:57:53 +01006223 ++unres_count;
Radek Krejci48464ed2016-03-17 15:44:09 +01006224 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006225 if (!rc) {
Michal Vasko51054ca2015-08-12 12:20:00 +02006226 unres->type[i] = UNRES_RESOLVED;
6227 ++resolved;
Michal Vasko88c29542015-11-27 14:57:53 +01006228 ++res_count;
Michal Vasko89e15322015-08-17 15:46:55 +02006229 } else if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006230 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006231 /* print the error */
6232 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006233 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02006234 } else {
6235 /* forward reference, erase ly_errno */
6236 ly_errno = LY_SUCCESS;
6237 ly_vecode = LYVE_SUCCESS;
Michal Vasko51054ca2015-08-12 12:20:00 +02006238 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006239 }
Michal Vasko88c29542015-11-27 14:57:53 +01006240 } while (res_count && (res_count < unres_count));
Michal Vasko51054ca2015-08-12 12:20:00 +02006241
Michal Vasko88c29542015-11-27 14:57:53 +01006242 if (res_count < unres_count) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006243 /* just print the errors */
6244 ly_vlog_hide(0);
6245
6246 for (i = 0; i < unres->count; ++i) {
Radek Krejci018f1f52016-08-03 16:01:20 +02006247 if (unres->type[i] > UNRES_IDENT) {
Michal Vasko22af5ca2016-05-20 11:44:02 +02006248 continue;
6249 }
6250 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6251 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006252 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006253 }
6254
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006255 /* the rest */
6256 for (i = 0; i < unres->count; ++i) {
6257 if (unres->type[i] == UNRES_RESOLVED) {
6258 continue;
6259 }
Michal Vaskoc07187d2015-08-13 15:20:57 +02006260
Radek Krejci48464ed2016-03-17 15:44:09 +01006261 rc = resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006262 if (rc == 0) {
Pavol Vican88e16c92016-09-07 15:41:50 +02006263 if (unres->type[i] == UNRES_LIST_UNIQ) {
6264 /* free the allocated structure */
6265 free(unres->item[i]);
6266 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006267 unres->type[i] = UNRES_RESOLVED;
6268 ++resolved;
6269 } else if (rc == -1) {
6270 ly_vlog_hide(0);
Michal Vasko22af5ca2016-05-20 11:44:02 +02006271 /* print the error */
6272 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
6273 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006274 }
6275 }
6276
Radek Krejci010e54b2016-03-15 09:40:34 +01006277 ly_vlog_hide(0);
6278
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006279 if (resolved < unres->count) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006280 /* try to resolve the unresolved nodes again, it will not resolve anything, but it will print
6281 * all the validation errors
6282 */
6283 for (i = 0; i < unres->count; ++i) {
6284 if (unres->type[i] == UNRES_RESOLVED) {
6285 continue;
6286 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006287 resolve_unres_schema_item(mod, unres->item[i], unres->type[i], unres->str_snode[i], unres);
Radek Krejci010e54b2016-03-15 09:40:34 +01006288 }
Michal Vasko92b8a382015-08-19 14:03:49 +02006289 return -1;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006290 }
6291
Michal Vaskoe8734262016-09-29 14:12:06 +02006292 LOGVRB("All \"%s\" schema nodes and constraints resolved.", mod->name);
Radek Krejcic071c542016-01-27 14:57:51 +01006293 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006294 return EXIT_SUCCESS;
6295}
6296
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006297/**
Michal Vaskobb211122015-08-19 14:03:11 +02006298 * @brief Try to resolve an unres schema item with a string argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006299 *
6300 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006301 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006302 * @param[in] item Item to resolve. Type determined by \p type.
6303 * @param[in] type Type of the unresolved item.
6304 * @param[in] str String argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006305 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006306 * @return EXIT_SUCCESS on success, EXIT_FAILURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006307 */
6308int
Radek Krejci48464ed2016-03-17 15:44:09 +01006309unres_schema_add_str(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
6310 const char *str)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006311{
Radek Krejci54081ce2016-08-12 15:21:47 +02006312 int rc;
6313 const char *dictstr;
6314
6315 dictstr = lydict_insert(mod->ctx, str, 0);
6316 rc = unres_schema_add_node(mod, unres, item, type, (struct lys_node *)dictstr);
6317
6318 if (rc == -1) {
6319 lydict_remove(mod->ctx, dictstr);
6320 }
6321 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006322}
6323
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006324/**
Michal Vaskobb211122015-08-19 14:03:11 +02006325 * @brief Try to resolve an unres schema item with a schema node argument. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006326 *
6327 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006328 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006329 * @param[in] item Item to resolve. Type determined by \p type.
Michal Vasko88c29542015-11-27 14:57:53 +01006330 * @param[in] type Type of the unresolved item. UNRES_TYPE_DER is handled specially!
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006331 * @param[in] snode Schema node argument.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006332 *
Michal Vasko3767fb22016-07-21 12:10:57 +02006333 * @return EXIT_SUCCESS on success, EXIT_FIALURE on storing the item in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006334 */
6335int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006336unres_schema_add_node(struct lys_module *mod, struct unres_schema *unres, void *item, enum UNRES_ITEM type,
Radek Krejci48464ed2016-03-17 15:44:09 +01006337 struct lys_node *snode)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006338{
Michal Vaskoef486d72016-09-27 12:10:44 +02006339 int rc, log_hidden;
Michal Vasko88c29542015-11-27 14:57:53 +01006340 struct lyxml_elem *yin;
Radek Krejci010e54b2016-03-15 09:40:34 +01006341 char *path, *msg;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006342
Michal Vasko9bf425b2015-10-22 11:42:03 +02006343 assert(unres && item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)
6344 && (type != UNRES_MUST)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006345
Michal Vaskoef486d72016-09-27 12:10:44 +02006346 if (*ly_vlog_hide_location()) {
6347 log_hidden = 1;
6348 } else {
6349 log_hidden = 0;
6350 ly_vlog_hide(1);
6351 }
Radek Krejci48464ed2016-03-17 15:44:09 +01006352 rc = resolve_unres_schema_item(mod, item, type, snode, unres);
Michal Vaskoef486d72016-09-27 12:10:44 +02006353 if (!log_hidden) {
6354 ly_vlog_hide(0);
6355 }
6356
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006357 if (rc != EXIT_FAILURE) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006358 if (rc == -1 && ly_errno == LY_EVALID) {
Radek Krejci76e15e12016-06-22 11:02:24 +02006359 if (ly_log_level >= LY_LLERR) {
6360 path = strdup(ly_errpath());
6361 msg = strdup(ly_errmsg());
6362 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6363 free(path);
6364 free(msg);
6365 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006366 }
Radek Krejcid09d1a52016-08-11 14:05:45 +02006367 if (type == UNRES_LIST_UNIQ) {
6368 /* free the allocated structure */
6369 free(item);
Pavol Vican88e16c92016-09-07 15:41:50 +02006370 } else if (rc == -1 && type == UNRES_IFFEAT) {
6371 /* free the allocated resources */
6372 free(*((char **)item));
6373 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006374 return rc;
Radek Krejcif347abc2016-06-22 10:18:47 +02006375 } else {
6376 /* erase info about validation errors */
6377 ly_errno = LY_SUCCESS;
6378 ly_vecode = LYVE_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006379 }
6380
Radek Krejci48464ed2016-03-17 15:44:09 +01006381 print_unres_schema_item_fail(item, type, snode);
Michal Vaskof02e3742015-08-05 16:27:02 +02006382
Michal Vasko88c29542015-11-27 14:57:53 +01006383 /* HACK unlinking is performed here so that we do not do any (NS) copying in vain */
Radek Krejci3a5501d2016-07-18 22:03:34 +02006384 if (type == UNRES_TYPE_DER || type == UNRES_TYPE_DER_TPDF) {
Michal Vasko88c29542015-11-27 14:57:53 +01006385 yin = (struct lyxml_elem *)((struct lys_type *)item)->der;
Pavol Vicana0e4e672016-02-24 12:20:04 +01006386 if (!(yin->flags & LY_YANG_STRUCTURE_FLAG)) {
6387 lyxml_unlink_elem(mod->ctx, yin, 1);
6388 ((struct lys_type *)item)->der = (struct lys_tpdf *)yin;
6389 }
Michal Vasko88c29542015-11-27 14:57:53 +01006390 }
6391
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006392 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006393 unres->item = ly_realloc(unres->item, unres->count*sizeof *unres->item);
6394 if (!unres->item) {
6395 LOGMEM;
6396 return -1;
6397 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006398 unres->item[unres->count-1] = item;
Michal Vasko253035f2015-12-17 16:58:13 +01006399 unres->type = ly_realloc(unres->type, unres->count*sizeof *unres->type);
6400 if (!unres->type) {
6401 LOGMEM;
6402 return -1;
6403 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006404 unres->type[unres->count-1] = type;
Michal Vasko253035f2015-12-17 16:58:13 +01006405 unres->str_snode = ly_realloc(unres->str_snode, unres->count*sizeof *unres->str_snode);
6406 if (!unres->str_snode) {
6407 LOGMEM;
6408 return -1;
6409 }
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006410 unres->str_snode[unres->count-1] = snode;
Radek Krejcic071c542016-01-27 14:57:51 +01006411 unres->module = ly_realloc(unres->module, unres->count*sizeof *unres->module);
6412 if (!unres->module) {
6413 LOGMEM;
6414 return -1;
6415 }
6416 unres->module[unres->count-1] = mod;
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006417
Michal Vasko3767fb22016-07-21 12:10:57 +02006418 return rc;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006419}
6420
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006421/**
Michal Vaskobb211122015-08-19 14:03:11 +02006422 * @brief Duplicate an unres schema item. Logs indirectly.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006423 *
6424 * @param[in] mod Main module.
Michal Vaskobb211122015-08-19 14:03:11 +02006425 * @param[in] unres Unres schema structure to use.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006426 * @param[in] item Old item to be resolved.
6427 * @param[in] type Type of the old unresolved item.
6428 * @param[in] new_item New item to use in the duplicate.
6429 *
Radek Krejci9ff0a922016-07-14 13:08:05 +02006430 * @return EXIT_SUCCESS on success, EXIT_FAILURE if item is not in unres, -1 on error.
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006431 */
Michal Vaskodad19402015-08-06 09:51:53 +02006432int
Michal Vasko0bd29d12015-08-19 11:45:49 +02006433unres_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 +02006434{
6435 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006436 struct unres_list_uniq aux_uniq;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006437 struct unres_iffeat_data *iff_data;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006438
Michal Vaskocf024702015-10-08 15:01:42 +02006439 assert(item && new_item && ((type != UNRES_LEAFREF) && (type != UNRES_INSTID) && (type != UNRES_WHEN)));
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006440
Radek Krejcid09d1a52016-08-11 14:05:45 +02006441 /* hack for UNRES_LIST_UNIQ, which stores multiple items behind its item */
6442 if (type == UNRES_LIST_UNIQ) {
6443 aux_uniq.list = item;
6444 aux_uniq.expr = ((struct unres_list_uniq *)new_item)->expr;
6445 item = &aux_uniq;
6446 }
Michal Vasko878e38d2016-09-05 12:17:53 +02006447 i = unres_schema_find(unres, -1, item, type);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006448
6449 if (i == -1) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006450 if (type == UNRES_LIST_UNIQ) {
6451 free(new_item);
6452 }
Radek Krejci9ff0a922016-07-14 13:08:05 +02006453 return EXIT_FAILURE;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006454 }
6455
Radek Krejcic79c6b12016-07-26 15:11:49 +02006456 if ((type == UNRES_TYPE_LEAFREF) || (type == UNRES_USES) || (type == UNRES_TYPE_DFLT) ||
Radek Krejcib69f3232016-09-16 17:41:07 +02006457 (type == UNRES_FEATURE) || (type == UNRES_LIST_UNIQ)) {
Radek Krejci48464ed2016-03-17 15:44:09 +01006458 if (unres_schema_add_node(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006459 LOGINT;
6460 return -1;
6461 }
Radek Krejcicbb473e2016-09-16 14:48:32 +02006462 } else if (type == UNRES_IFFEAT) {
6463 /* duplicate unres_iffeature_data */
6464 iff_data = malloc(sizeof *iff_data);
6465 iff_data->fname = lydict_insert(mod->ctx, ((struct unres_iffeat_data *)unres->str_snode[i])->fname, 0);
6466 iff_data->node = ((struct unres_iffeat_data *)unres->str_snode[i])->node;
6467 if (unres_schema_add_node(mod, unres, new_item, type, (struct lys_node *)iff_data) == -1) {
6468 LOGINT;
6469 return -1;
6470 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006471 } else {
Radek Krejci48464ed2016-03-17 15:44:09 +01006472 if (unres_schema_add_str(mod, unres, new_item, type, unres->str_snode[i]) == -1) {
Michal Vasko3ab70fc2015-08-17 14:06:23 +02006473 LOGINT;
6474 return -1;
6475 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006476 }
Michal Vaskodad19402015-08-06 09:51:53 +02006477
6478 return EXIT_SUCCESS;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006479}
6480
Michal Vaskof02e3742015-08-05 16:27:02 +02006481/* does not log */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006482int
Michal Vasko878e38d2016-09-05 12:17:53 +02006483unres_schema_find(struct unres_schema *unres, int start_on_backwards, void *item, enum UNRES_ITEM type)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006484{
Michal Vasko878e38d2016-09-05 12:17:53 +02006485 int i;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006486 struct unres_list_uniq *aux_uniq1, *aux_uniq2;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006487
Michal Vasko878e38d2016-09-05 12:17:53 +02006488 if (start_on_backwards > 0) {
6489 i = start_on_backwards;
6490 } else {
6491 i = unres->count - 1;
6492 }
6493 for (; i > -1; i--) {
6494 if (unres->type[i] != type) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006495 continue;
6496 }
6497 if (type != UNRES_LIST_UNIQ) {
Michal Vasko878e38d2016-09-05 12:17:53 +02006498 if (unres->item[i] == item) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006499 break;
6500 }
6501 } else {
6502 aux_uniq1 = (struct unres_list_uniq *)unres->item[i - 1];
6503 aux_uniq2 = (struct unres_list_uniq *)item;
6504 if ((aux_uniq1->list == aux_uniq2->list) && ly_strequal(aux_uniq1->expr, aux_uniq2->expr, 0)) {
Radek Krejcid09d1a52016-08-11 14:05:45 +02006505 break;
6506 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006507 }
6508 }
6509
Michal Vasko878e38d2016-09-05 12:17:53 +02006510 return i;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006511}
Michal Vasko8bcdf292015-08-19 14:04:43 +02006512
Michal Vaskoede9c472016-06-07 09:38:15 +02006513static void
6514unres_schema_free_item(struct ly_ctx *ctx, struct unres_schema *unres, uint32_t i)
6515{
6516 struct lyxml_elem *yin;
6517 struct yang_type *yang;
Radek Krejcicbb473e2016-09-16 14:48:32 +02006518 struct unres_iffeat_data *iff_data;
Michal Vaskoede9c472016-06-07 09:38:15 +02006519
6520 switch (unres->type[i]) {
Radek Krejci3a5501d2016-07-18 22:03:34 +02006521 case UNRES_TYPE_DER_TPDF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006522 case UNRES_TYPE_DER:
6523 yin = (struct lyxml_elem *)((struct lys_type *)unres->item[i])->der;
6524 if (yin->flags & LY_YANG_STRUCTURE_FLAG) {
6525 yang =(struct yang_type *)yin;
6526 yang->type->base = yang->base;
6527 lydict_remove(ctx, yang->name);
6528 free(yang);
6529 } else {
6530 lyxml_free(ctx, yin);
6531 }
6532 break;
Pavol Vican88e16c92016-09-07 15:41:50 +02006533 case UNRES_IFFEAT:
Radek Krejcicbb473e2016-09-16 14:48:32 +02006534 iff_data = (struct unres_iffeat_data *)unres->str_snode[i];
6535 lydict_remove(ctx, iff_data->fname);
6536 free(unres->str_snode[i]);
Pavol Vican88e16c92016-09-07 15:41:50 +02006537 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006538 case UNRES_IDENT:
6539 case UNRES_TYPE_IDENTREF:
Michal Vaskoede9c472016-06-07 09:38:15 +02006540 case UNRES_TYPE_DFLT:
6541 case UNRES_CHOICE_DFLT:
6542 case UNRES_LIST_KEYS:
Michal Vaskoede9c472016-06-07 09:38:15 +02006543 lydict_remove(ctx, (const char *)unres->str_snode[i]);
6544 break;
Radek Krejcid09d1a52016-08-11 14:05:45 +02006545 case UNRES_LIST_UNIQ:
6546 free(unres->item[i]);
6547 break;
Michal Vaskoede9c472016-06-07 09:38:15 +02006548 default:
6549 break;
6550 }
6551 unres->type[i] = UNRES_RESOLVED;
6552}
6553
Michal Vasko88c29542015-11-27 14:57:53 +01006554void
Radek Krejcic071c542016-01-27 14:57:51 +01006555unres_schema_free(struct lys_module *module, struct unres_schema **unres)
Michal Vasko88c29542015-11-27 14:57:53 +01006556{
6557 uint32_t i;
Radek Krejcic071c542016-01-27 14:57:51 +01006558 unsigned int unresolved = 0;
Michal Vasko88c29542015-11-27 14:57:53 +01006559
Radek Krejcic071c542016-01-27 14:57:51 +01006560 if (!unres || !(*unres)) {
6561 return;
Michal Vasko88c29542015-11-27 14:57:53 +01006562 }
6563
Radek Krejcic071c542016-01-27 14:57:51 +01006564 assert(module || (*unres)->count == 0);
6565
6566 for (i = 0; i < (*unres)->count; ++i) {
6567 if ((*unres)->module[i] != module) {
6568 if ((*unres)->type[i] != UNRES_RESOLVED) {
6569 unresolved++;
6570 }
6571 continue;
6572 }
Michal Vaskoede9c472016-06-07 09:38:15 +02006573
6574 /* free heap memory for the specific item */
6575 unres_schema_free_item(module->ctx, *unres, i);
Radek Krejcic071c542016-01-27 14:57:51 +01006576 }
6577
Michal Vaskoede9c472016-06-07 09:38:15 +02006578 /* free it all */
Radek Krejcic071c542016-01-27 14:57:51 +01006579 if (!module || (!unresolved && !module->type)) {
6580 free((*unres)->item);
6581 free((*unres)->type);
6582 free((*unres)->str_snode);
6583 free((*unres)->module);
Radek Krejcic071c542016-01-27 14:57:51 +01006584 free((*unres));
6585 (*unres) = NULL;
6586 }
Michal Vasko88c29542015-11-27 14:57:53 +01006587}
6588
Radek Krejci9b6aad22016-09-20 15:55:51 +02006589static int resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type);
6590
Radek Krejci7de36cf2016-09-12 16:18:50 +02006591static int
Radek Krejci9b6aad22016-09-20 15:55:51 +02006592resolve_leafref(struct lyd_node_leaf_list *leaf, struct lys_type *type)
Radek Krejci7de36cf2016-09-12 16:18:50 +02006593{
Radek Krejci7de36cf2016-09-12 16:18:50 +02006594 struct unres_data matches;
6595 uint32_t i;
6596
Radek Krejci9b6aad22016-09-20 15:55:51 +02006597 assert(type->base == LY_TYPE_LEAFREF);
6598
6599 /* init */
Radek Krejci7de36cf2016-09-12 16:18:50 +02006600 memset(&matches, 0, sizeof matches);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006601
6602 /* EXIT_FAILURE return keeps leaf->value.lefref NULL, handled later */
Radek Krejci9b6aad22016-09-20 15:55:51 +02006603 if (resolve_path_arg_data((struct lyd_node *)leaf, type->info.lref.path, &matches) == -1) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02006604 return -1;
6605 }
6606
6607 /* check that value matches */
6608 for (i = 0; i < matches.count; ++i) {
6609 if (ly_strequal(leaf->value_str, ((struct lyd_node_leaf_list *)matches.node[i])->value_str, 1)) {
6610 leaf->value.leafref = matches.node[i];
6611 break;
6612 }
6613 }
6614
6615 free(matches.node);
6616
6617 if (!leaf->value.leafref) {
6618 /* reference not found */
6619 if (type->info.lref.req > -1) {
6620 LOGVAL(LYE_NOLEAFREF, LY_VLOG_LYD, leaf, type->info.lref.path, leaf->value_str);
6621 return EXIT_FAILURE;
6622 } else {
6623 LOGVRB("There is no leafref with the value \"%s\", but it is not required.", leaf->value_str);
6624 }
6625 }
6626
6627 return EXIT_SUCCESS;
6628}
6629
Radek Krejci9b6aad22016-09-20 15:55:51 +02006630API LY_DATA_TYPE
6631lyd_leaf_type(const struct lyd_node_leaf_list *leaf)
6632{
6633 struct lyd_node *node;
6634 struct lys_type *type, *type_iter;
6635 lyd_val value;
6636 int f = 0, r;
6637
6638 if (!leaf || !(leaf->schema->nodetype & (LYS_LEAF | LYS_LEAFLIST))) {
6639 return LY_TYPE_ERR;
6640 }
6641
6642 if (leaf->value_type > 0 && (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_UNION &&
6643 (leaf->value_type & LY_DATA_TYPE_MASK) != LY_TYPE_LEAFREF) {
6644 /* we can get the type directly from the data node (it was already resolved) */
6645 return leaf->value_type & LY_DATA_TYPE_MASK;
6646 }
6647
6648 /* init */
6649 type = &((struct lys_node_leaf *)leaf->schema)->type;
6650 value = leaf->value;
6651 ly_vlog_hide(1);
6652
6653 /* resolve until we get the real data type */
6654 while (1) {
6655 /* get the correct data type from schema */
6656 switch (type->base) {
6657 case LY_TYPE_LEAFREF:
6658 type = &type->info.lref.target->type;
6659 break; /* continue in while loop */
6660 case LY_TYPE_UNION:
6661 type_iter = NULL;
6662 while ((type_iter = lyp_get_next_union_type(type, type_iter, &f))) {
6663 if (type_iter->base == LY_TYPE_LEAFREF) {
6664 if (type_iter->info.lref.req == -1) {
6665 /* target not required, so it always succeeds */
6666 break;
6667 } else {
6668 /* try to resolve leafref */
6669 memset(&((struct lyd_node_leaf_list *)leaf)->value, 0, sizeof leaf->value);
6670 r = resolve_leafref((struct lyd_node_leaf_list *)leaf, type_iter);
6671 /* revert leaf's content affected by resolve_leafref */
6672 ((struct lyd_node_leaf_list *)leaf)->value = value;
6673 if (!r) {
6674 /* success, we can continue with the leafref type */
6675 break;
6676 }
6677 }
6678 } else if (type_iter->base == LY_TYPE_INST) {
6679 if (type_iter->info.inst.req == -1) {
6680 /* target not required, so it always succeeds */
6681 return LY_TYPE_INST;
6682 } else {
6683 /* try to resolve instance-identifier */
6684 ly_errno = 0;
6685 node = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6686 if (!ly_errno && node) {
6687 /* the real type is instance-identifier */
6688 return LY_TYPE_INST;
6689 }
6690 }
6691 } else {
6692 r = lyp_parse_value_type((struct lyd_node_leaf_list *)leaf, type_iter, 1);
6693 /* revert leaf's content affected by resolve_leafref */
6694 ((struct lyd_node_leaf_list *)leaf)->value = value;
6695 if (!r) {
6696 /* we have the real type */
6697 return type_iter->base;
6698 }
6699 }
6700 f = 0;
6701 }
6702 /* erase ly_errno and ly_vecode */
6703 ly_errno = LY_SUCCESS;
6704 ly_vecode = LYVE_SUCCESS;
6705
6706 if (!type_iter) {
6707 LOGERR(LY_EINVAL, "Unable to get type from union \"%s\" with no valid type.", type->parent->name)
6708 return LY_TYPE_ERR;
6709 }
6710 type = type_iter;
6711 break;
6712 default:
6713 /* we have the real type */
6714 ly_vlog_hide(0);
6715 return type->base;
6716 }
6717 }
6718
6719 ly_vlog_hide(0);
6720 return LY_TYPE_ERR;
6721}
6722
6723static int
6724resolve_union(struct lyd_node_leaf_list *leaf, struct lys_type *type)
6725{
6726 struct lys_type *datatype = NULL;
6727 int f = 0;
6728
6729 assert(type->base == LY_TYPE_UNION);
6730
6731 memset(&leaf->value, 0, sizeof leaf->value);
6732 while ((datatype = lyp_get_next_union_type(type, datatype, &f))) {
6733 leaf->value_type = datatype->base;
6734
6735 if (datatype->base == LY_TYPE_LEAFREF) {
6736 /* try to resolve leafref */
6737 if (!resolve_leafref(leaf, datatype)) {
6738 /* success */
6739 break;
6740 }
6741 } else if (datatype->base == LY_TYPE_INST) {
6742 /* try to resolve instance-identifier */
6743 ly_errno = 0;
6744 leaf->value.instance = resolve_instid((struct lyd_node *)leaf, leaf->value_str);
6745 if (!ly_errno && (leaf->value.instance || datatype->info.inst.req == -1)) {
6746 /* success */
6747 break;
6748 }
6749 } else {
6750 if (!lyp_parse_value_type(leaf, datatype, 1)) {
6751 /* success */
6752 break;
6753 }
6754 }
6755 f = 0;
6756 }
6757 /* erase ly_errno and ly_vecode */
6758 ly_errno = LY_SUCCESS;
6759 ly_vecode = LYVE_SUCCESS;
6760
6761 if (!datatype) {
6762 /* failure */
6763 LOGVAL(LYE_INVAL, LY_VLOG_LYD, leaf, (leaf->value_str ? leaf->value_str : ""), leaf->schema->name);
6764 return EXIT_FAILURE;
6765 }
6766
6767 return EXIT_SUCCESS;
6768}
6769
Michal Vasko8bcdf292015-08-19 14:04:43 +02006770/**
6771 * @brief Resolve a single unres data item. Logs directly.
6772 *
Michal Vaskocf024702015-10-08 15:01:42 +02006773 * @param[in] node Data node to resolve.
Michal Vaskocf024702015-10-08 15:01:42 +02006774 * @param[in] type Type of the unresolved item.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006775 *
6776 * @return EXIT_SUCCESS on success, EXIT_FAILURE on forward reference, -1 on error.
6777 */
Michal Vasko8ea2b7f2015-09-29 14:30:53 +02006778int
Radek Krejci48464ed2016-03-17 15:44:09 +01006779resolve_unres_data_item(struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006780{
Michal Vasko0491ab32015-08-19 14:28:29 +02006781 int rc;
Michal Vasko83a6c462015-10-08 16:43:53 +02006782 struct lyd_node_leaf_list *leaf;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006783 struct lys_node_leaf *sleaf;
Michal Vaskoc4280842016-04-19 16:10:42 +02006784 struct lyd_node *parent;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006785
Michal Vasko83a6c462015-10-08 16:43:53 +02006786 leaf = (struct lyd_node_leaf_list *)node;
Michal Vaskocf024702015-10-08 15:01:42 +02006787 sleaf = (struct lys_node_leaf *)leaf->schema;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006788
Michal Vaskocf024702015-10-08 15:01:42 +02006789 switch (type) {
6790 case UNRES_LEAFREF:
6791 assert(sleaf->type.base == LY_TYPE_LEAFREF);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006792 return resolve_leafref(leaf, &sleaf->type);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006793
Michal Vaskocf024702015-10-08 15:01:42 +02006794 case UNRES_INSTID:
Radek Krejci7de36cf2016-09-12 16:18:50 +02006795 assert(sleaf->type.base == LY_TYPE_INST);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006796 ly_errno = 0;
Radek Krejci48464ed2016-03-17 15:44:09 +01006797 leaf->value.instance = resolve_instid(node, leaf->value_str);
Radek Krejci40f17b92016-02-03 14:30:43 +01006798 if (!leaf->value.instance) {
Michal Vasko8bcdf292015-08-19 14:04:43 +02006799 if (ly_errno) {
6800 return -1;
6801 } else if (sleaf->type.info.inst.req > -1) {
Michal Vasko6ac68282016-04-11 10:56:47 +02006802 LOGVAL(LYE_NOREQINS, LY_VLOG_LYD, leaf, leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006803 return EXIT_FAILURE;
6804 } else {
Michal Vasko9925e282016-09-02 12:45:14 +02006805 LOGVRB("There is no instance identifier \"%s\", but it is not required.", leaf->value_str);
Michal Vasko8bcdf292015-08-19 14:04:43 +02006806 }
6807 }
Michal Vaskocf024702015-10-08 15:01:42 +02006808 break;
6809
Radek Krejci7de36cf2016-09-12 16:18:50 +02006810 case UNRES_UNION:
6811 assert(sleaf->type.base == LY_TYPE_UNION);
Radek Krejci9b6aad22016-09-20 15:55:51 +02006812 return resolve_union(leaf, &sleaf->type);
Radek Krejci7de36cf2016-09-12 16:18:50 +02006813
Michal Vaskocf024702015-10-08 15:01:42 +02006814 case UNRES_WHEN:
Radek Krejci46165822016-08-26 14:06:27 +02006815 if ((rc = resolve_when(node, NULL))) {
Michal Vaskocf024702015-10-08 15:01:42 +02006816 return rc;
6817 }
6818 break;
6819
Michal Vaskobf19d252015-10-08 15:39:17 +02006820 case UNRES_MUST:
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006821 if ((rc = resolve_must(node, 0))) {
6822 return rc;
6823 }
6824 break;
6825
6826 case UNRES_MUST_INOUT:
6827 if ((rc = resolve_must(node, 1))) {
Michal Vaskobf19d252015-10-08 15:39:17 +02006828 return rc;
6829 }
6830 break;
6831
Michal Vaskoc4280842016-04-19 16:10:42 +02006832 case UNRES_EMPTYCONT:
6833 do {
6834 parent = node->parent;
6835 lyd_free(node);
6836 node = parent;
6837 } while (node && (node->schema->nodetype == LYS_CONTAINER) && !node->child
6838 && !((struct lys_node_container *)node->schema)->presence);
6839 break;
6840
Michal Vaskocf024702015-10-08 15:01:42 +02006841 default:
Michal Vasko8bcdf292015-08-19 14:04:43 +02006842 LOGINT;
6843 return -1;
6844 }
6845
6846 return EXIT_SUCCESS;
6847}
6848
6849/**
Radek Krejci0b7704f2016-03-18 12:16:14 +01006850 * @brief add data unres item
Michal Vasko8bcdf292015-08-19 14:04:43 +02006851 *
6852 * @param[in] unres Unres data structure to use.
Michal Vaskocf024702015-10-08 15:01:42 +02006853 * @param[in] node Data node to use.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006854 *
Radek Krejci0b7704f2016-03-18 12:16:14 +01006855 * @return 0 on success, -1 on error.
Michal Vasko8bcdf292015-08-19 14:04:43 +02006856 */
6857int
Radek Krejci0b7704f2016-03-18 12:16:14 +01006858unres_data_add(struct unres_data *unres, struct lyd_node *node, enum UNRES_ITEM type)
Michal Vasko8bcdf292015-08-19 14:04:43 +02006859{
Radek Krejci03b71f72016-03-16 11:10:09 +01006860 assert(unres && node);
Michal Vaskoc4280842016-04-19 16:10:42 +02006861 assert((type == UNRES_LEAFREF) || (type == UNRES_INSTID) || (type == UNRES_WHEN) || (type == UNRES_MUST)
Michal Vaskoc8c810c2016-09-15 14:02:00 +02006862 || (type == UNRES_MUST_INOUT) || (type == UNRES_UNION) || (type == UNRES_EMPTYCONT));
Michal Vasko8bcdf292015-08-19 14:04:43 +02006863
Radek Krejci03b71f72016-03-16 11:10:09 +01006864 unres->count++;
Michal Vasko253035f2015-12-17 16:58:13 +01006865 unres->node = ly_realloc(unres->node, unres->count * sizeof *unres->node);
6866 if (!unres->node) {
6867 LOGMEM;
6868 return -1;
6869 }
Michal Vaskocf024702015-10-08 15:01:42 +02006870 unres->node[unres->count - 1] = node;
Michal Vasko253035f2015-12-17 16:58:13 +01006871 unres->type = ly_realloc(unres->type, unres->count * sizeof *unres->type);
6872 if (!unres->type) {
6873 LOGMEM;
6874 return -1;
6875 }
Michal Vaskocf024702015-10-08 15:01:42 +02006876 unres->type[unres->count - 1] = type;
Michal Vasko8bcdf292015-08-19 14:04:43 +02006877
Radek Krejci0b7704f2016-03-18 12:16:14 +01006878 if (type == UNRES_WHEN) {
6879 /* remove previous result */
6880 node->when_status = LYD_WHEN;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006881 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006882
6883 return EXIT_SUCCESS;
6884}
6885
6886/**
6887 * @brief Resolve every unres data item in the structure. Logs directly.
6888 *
Radek Krejci082c84f2016-10-17 16:33:06 +02006889 * If options includes LYD_OPT_TRUSTED, the data are considered trusted (when, must conditions are not expected,
6890 * unresolved leafrefs/instids are accepted).
6891 *
6892 * If options includes LYD_OPT_NOAUTODEL, the false resulting when condition on non-default nodes, the error is raised.
6893 *
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006894 * @param[in] unres Unres data structure to use.
Radek Krejci082c84f2016-10-17 16:33:06 +02006895 * @param[in,out] root Root node of the data tree, can be changed due to autodeletion.
6896 * @param[in] options Data options as described above.
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006897 *
6898 * @return EXIT_SUCCESS on success, -1 on error.
6899 */
6900int
Radek Krejci082c84f2016-10-17 16:33:06 +02006901resolve_unres_data(struct unres_data *unres, struct lyd_node **root, int options)
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006902{
Radek Krejci0c0086a2016-03-24 15:20:28 +01006903 uint32_t i, j, first = 1, resolved = 0, del_items = 0, when_stmt = 0;
Radek Krejci010e54b2016-03-15 09:40:34 +01006904 int rc, progress;
Radek Krejci03b71f72016-03-16 11:10:09 +01006905 char *msg, *path;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006906 struct lyd_node *parent;
Radek Krejci7de36cf2016-09-12 16:18:50 +02006907 struct lyd_node_leaf_list *leaf;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006908
Radek Krejci082c84f2016-10-17 16:33:06 +02006909 assert(root);
Radek Krejci03b71f72016-03-16 11:10:09 +01006910 assert(unres);
Radek Krejci03b71f72016-03-16 11:10:09 +01006911
6912 if (!unres->count) {
6913 return EXIT_SUCCESS;
6914 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02006915
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02006916 LOGVRB("Resolving unresolved data nodes and their constraints...");
Radek Krejci010e54b2016-03-15 09:40:34 +01006917 ly_vlog_hide(1);
6918
Radek Krejci0b7704f2016-03-18 12:16:14 +01006919 /* when-stmt first */
Radek Krejci03b71f72016-03-16 11:10:09 +01006920 ly_errno = LY_SUCCESS;
6921 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01006922 do {
6923 progress = 0;
Michal Vasko6df94132016-09-22 11:08:09 +02006924 for (i = 0; i < unres->count; i++) {
Radek Krejci010e54b2016-03-15 09:40:34 +01006925 if (unres->type[i] != UNRES_WHEN) {
6926 continue;
6927 }
Radek Krejci082c84f2016-10-17 16:33:06 +02006928 assert(!(options & LYD_OPT_TRUSTED));
Radek Krejci0c0086a2016-03-24 15:20:28 +01006929 if (first) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006930 /* count when-stmt nodes in unres list */
6931 when_stmt++;
6932 }
6933
6934 /* resolve when condition only when all parent when conditions are already resolved */
6935 for (parent = unres->node[i]->parent;
6936 parent && LYD_WHEN_DONE(parent->when_status);
6937 parent = parent->parent) {
6938 if (!parent->parent && (parent->when_status & LYD_WHEN_FALSE)) {
6939 /* the parent node was already unlinked, do not resolve this node,
6940 * it will be removed anyway, so just mark it as resolved
6941 */
6942 unres->node[i]->when_status |= LYD_WHEN_FALSE;
6943 unres->type[i] = UNRES_RESOLVED;
6944 resolved++;
6945 break;
6946 }
6947 }
6948 if (parent) {
6949 continue;
6950 }
Radek Krejci010e54b2016-03-15 09:40:34 +01006951
Radek Krejci48464ed2016-03-17 15:44:09 +01006952 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01006953 if (!rc) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006954 if (unres->node[i]->when_status & LYD_WHEN_FALSE) {
Radek Krejci082c84f2016-10-17 16:33:06 +02006955 if ((options & LYD_OPT_NOAUTODEL) && !unres->node[i]->dflt) {
Radek Krejci03b71f72016-03-16 11:10:09 +01006956 /* false when condition */
6957 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02006958 if (ly_log_level >= LY_LLERR) {
6959 path = strdup(ly_errpath());
6960 msg = strdup(ly_errmsg());
6961 LOGERR(LY_EVALID, "%s%s%s%s", msg,
6962 path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
6963 free(path);
6964 free(msg);
6965 }
Radek Krejci03b71f72016-03-16 11:10:09 +01006966 return -1;
Radek Krejci0b7704f2016-03-18 12:16:14 +01006967 } /* follows else */
6968
Radek Krejci0c0086a2016-03-24 15:20:28 +01006969 /* only unlink now, the subtree can contain another nodes stored in the unres list */
6970 /* if it has parent non-presence containers that would be empty, we should actually
6971 * remove the container
6972 */
Radek Krejci2537fd32016-09-07 16:22:41 +02006973 for (parent = unres->node[i];
6974 parent->parent && parent->parent->schema->nodetype == LYS_CONTAINER;
6975 parent = parent->parent) {
6976 if (((struct lys_node_container *)parent->parent->schema)->presence) {
6977 /* presence container */
6978 break;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006979 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006980 if (parent->next || parent->prev != parent) {
6981 /* non empty (the child we are in and we are going to remove is not the only child) */
6982 break;
6983 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01006984 }
Radek Krejci2537fd32016-09-07 16:22:41 +02006985 unres->node[i] = parent;
Radek Krejci0c0086a2016-03-24 15:20:28 +01006986
Radek Krejci0b7704f2016-03-18 12:16:14 +01006987 /* auto-delete */
6988 LOGVRB("auto-delete node \"%s\" due to when condition (%s)", ly_errpath(),
6989 ((struct lys_node_leaf *)unres->node[i]->schema)->when->cond);
Radek Krejci0c0086a2016-03-24 15:20:28 +01006990 if (*root && *root == unres->node[i]) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01006991 *root = (*root)->next;
Radek Krejci03b71f72016-03-16 11:10:09 +01006992 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01006993
Radek Krejci0b7704f2016-03-18 12:16:14 +01006994 lyd_unlink(unres->node[i]);
6995 unres->type[i] = UNRES_DELETE;
6996 del_items++;
Radek Krejci51fd8162016-03-24 15:49:51 +01006997
6998 /* update the rest of unres items */
6999 for (j = 0; j < unres->count; j++) {
Radek Krejci3db819b2016-03-24 16:29:48 +01007000 if (unres->type[j] == UNRES_RESOLVED || unres->type[j] == UNRES_DELETE) {
Radek Krejci51fd8162016-03-24 15:49:51 +01007001 continue;
7002 }
7003
7004 /* test if the node is in subtree to be deleted */
7005 for (parent = unres->node[j]; parent; parent = parent->parent) {
7006 if (parent == unres->node[i]) {
7007 /* yes, it is */
7008 unres->type[j] = UNRES_RESOLVED;
7009 resolved++;
7010 break;
7011 }
7012 }
7013 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007014 } else {
7015 unres->type[i] = UNRES_RESOLVED;
Radek Krejci03b71f72016-03-16 11:10:09 +01007016 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007017 ly_errno = LY_SUCCESS;
7018 ly_vecode = LYVE_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007019 resolved++;
7020 progress = 1;
7021 } else if (rc == -1) {
7022 ly_vlog_hide(0);
Michal Vasko76e73402016-08-24 16:00:13 +02007023 /* print only this last error */
7024 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007025 return -1;
Radek Krejcic2a180f2016-06-22 13:28:16 +02007026 } else {
7027 /* forward reference, erase ly_errno */
7028 ly_errno = LY_SUCCESS;
Radek Krejci010e54b2016-03-15 09:40:34 +01007029 }
7030 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007031 first = 0;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007032 } while (progress && resolved < when_stmt);
Radek Krejci010e54b2016-03-15 09:40:34 +01007033
Radek Krejci0b7704f2016-03-18 12:16:14 +01007034 /* do we have some unresolved when-stmt? */
Radek Krejcid940d732016-03-24 16:02:28 +01007035 if (when_stmt > resolved) {
Radek Krejci0b7704f2016-03-18 12:16:14 +01007036 ly_vlog_hide(0);
Radek Krejci76e15e12016-06-22 11:02:24 +02007037 if (ly_log_level >= LY_LLERR) {
7038 path = strdup(ly_errpath());
7039 msg = strdup(ly_errmsg());
7040 LOGERR(LY_EVALID, "%s%s%s%s", msg, path[0] ? " (path: " : "", path[0] ? path : "", path[0] ? ")" : "");
7041 free(path);
7042 free(msg);
7043 }
Radek Krejci0b7704f2016-03-18 12:16:14 +01007044 return -1;
7045 }
7046
7047 for (i = 0; del_items && i < unres->count; i++) {
7048 /* we had some when-stmt resulted to false, so now we have to sanitize the unres list */
7049 if (unres->type[i] != UNRES_DELETE) {
7050 continue;
7051 }
Radek Krejci0c0086a2016-03-24 15:20:28 +01007052 if (!unres->node[i]) {
7053 unres->type[i] = UNRES_RESOLVED;
7054 del_items--;
7055 continue;
Radek Krejci0b7704f2016-03-18 12:16:14 +01007056 }
7057
7058 /* really remove the complete subtree */
7059 lyd_free(unres->node[i]);
7060 unres->type[i] = UNRES_RESOLVED;
7061 del_items--;
7062 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007063
7064 /* rest */
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007065 for (i = 0; i < unres->count; ++i) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007066 if (unres->type[i] == UNRES_RESOLVED) {
7067 continue;
7068 }
Radek Krejci082c84f2016-10-17 16:33:06 +02007069 assert(!(options & LYD_OPT_TRUSTED) || ((unres->type[i] != UNRES_MUST) && (unres->type[i] != UNRES_MUST_INOUT)));
Radek Krejci010e54b2016-03-15 09:40:34 +01007070
Radek Krejci48464ed2016-03-17 15:44:09 +01007071 rc = resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vasko6df94132016-09-22 11:08:09 +02007072 if (rc == -1) {
Radek Krejci010e54b2016-03-15 09:40:34 +01007073 ly_vlog_hide(0);
Michal Vasko96b846c2016-05-18 13:28:58 +02007074 /* print only this last error */
7075 resolve_unres_data_item(unres->node[i], unres->type[i]);
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007076 return -1;
Radek Krejci082c84f2016-10-17 16:33:06 +02007077 } else if ((rc == 0) || ((options & LYD_OPT_TRUSTED) && ((unres->type[i] == UNRES_LEAFREF) || (unres->type[i] == UNRES_INSTID)))) {
Michal Vasko6df94132016-09-22 11:08:09 +02007078 unres->type[i] = UNRES_RESOLVED;
7079 resolved++;
Radek Krejci082c84f2016-10-17 16:33:06 +02007080 if (options & LYD_OPT_TRUSTED) {
Michal Vasko6df94132016-09-22 11:08:09 +02007081 /* accept it in this case */
7082 if (unres->type[i] == UNRES_LEAFREF) {
7083 LOGVRB("Leafref \"%s\" with value \"%s\" failed to be resolved.",
7084 ((struct lys_node_leaf *)unres->node[i]->schema)->type.info.lref.path,
7085 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7086 } else {
7087 LOGVRB("Instance identifier \"%s\" failed to be resolved.",
7088 ((struct lyd_node_leaf_list *)unres->node[i])->value_str);
7089 }
7090 }
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007091 }
7092 }
7093
Radek Krejci010e54b2016-03-15 09:40:34 +01007094 ly_vlog_hide(0);
7095 if (resolved < unres->count) {
7096 /* try to resolve the unresolved data again, it will not resolve anything, but it will print
7097 * all the validation errors
7098 */
7099 for (i = 0; i < unres->count; ++i) {
Radek Krejci7de36cf2016-09-12 16:18:50 +02007100 if (unres->type[i] == UNRES_UNION) {
7101 /* does not make sense to print specific errors for all
7102 * the data types, just print that the value is invalid */
7103 leaf = (struct lyd_node_leaf_list *)unres->node[i];
7104 LOGVAL(LYE_INVAL, LY_VLOG_LYD, unres->node[i], (leaf->value_str ? leaf->value_str : ""),
7105 leaf->schema->name);
7106 } else if (unres->type[i] != UNRES_RESOLVED) {
7107 resolve_unres_data_item(unres->node[i], unres->type[i]);
Radek Krejci010e54b2016-03-15 09:40:34 +01007108 }
Radek Krejci010e54b2016-03-15 09:40:34 +01007109 }
7110 return -1;
7111 }
7112
Michal Vaskoa0ffcab2016-05-02 14:52:08 +02007113 LOGVRB("All data nodes and constraints resolved.");
Radek Krejci010e54b2016-03-15 09:40:34 +01007114 unres->count = 0;
Michal Vaskoc3d9f8c2015-07-31 14:37:24 +02007115 return EXIT_SUCCESS;
7116}